프로그래밍/스크립트

HTTP 인증규약

라제폰 2008. 12. 9. 09:13

HTTP 인증규약

 

웹 서버가 문서를 보내기 전에 사용자의 접근 권한을 확인하기 위해 ID와 암호를 요구한다.

 

          웹                                            클라이언트

1. 일반적인 요청헤더전송                     2. WWW-Authenticate 인증 반응 헤더와 함께 오류메시지전송

3. 전송받은 WWW-Authenticate           4. 인증 정보 확인 후 문서 전송

    헤더와 인증정보를 포함하는

    Authorization 헤더를 포함시켜

    다시 접속

 

- 웹 클라이언트와 서버는 HTTP 요청/응답 헤더 WWW-Authenticate, Authorization을 사용하여 인증 정보를 교환한다.

- HTTP 기본 인증규약에는 웹 클라이언트가 사용자로 입력 받은 사용자 ID와 암호를 BASE64 인코딩하여 Authorization 헤더에 포함시켜 전송한다.(네트워크 스니퍼에 의한 공격에 취약하다.)

- 웹 브라우저는 재실행되기 전까지는 사용자로 부터 입력받은 인증 정보를 재사용하여 전송해준다.

- 일부 웹 서버( 아파치 웹 서버등) 의 경우, 특정 디렉토리를 기본 인증 규약을 사용하여 간단한 방법으로 암호를 걸어 놓을 수 있는 방법을 지원한다.

- 프록시 서버에도 암호를 걸어 놓을 수 있다.

 

관련문서

http://www.kol.co.kr/~cgklyk/index1.html

http://www.he.net/info/htaccess/demo.html

 

 

★ 기본 인증 규약 실행 예

- 아파치 웹 서버의 경우에는 웹 문서 디렉토리내에 다음과 같은 화일을 만들어 놓음으로써 해당 디렉토리에 암호를 걸어 놓을 수 있다.

- 다음 .htaccess 파일의 내용을 암호를 걸어놓을 디렉토리 (~public_html/example/web/passwd)에 가져다가 놓는다.

AuthName      "Basic Authentication Test"

AuthType       Basic

AuthUserFile  /home/me/public_html/example/passwd/.htpasswd

AuthGroupFile /dev/null

<Limit GET POST>

require          valid-user

</Limit>

 

암호를 걸어놓을 디렉토리에 사용자이름 및 Crypt.java를 사용하여 암호화된 암호를 .htpasswd파일에 저장한다.

( web/Crypt.java ) java Crypt myname mypass > .htpasswd

- http://myserver.com/~me/example/passwd/ 를 웹브라우저로 방문한후 대화상자가 뜨면 사요자 이름과 암호로 각각 myname과 mypass를 입력한다.

- HTTPClient.java로 접속하여 실제로 교환되는 자료의 내용을 조사한다.

java HttpClient myserver.com

GET /~me/example/passwd HTTP/1.0

 

^Z

........

HTTPClient.java로 인증 정보와 함께 접속한다. 이때, Authorization 요청헤더에 "사용자ID:암호" 형태의 인증정보를 Base64 인코딩하여 포함시킨후 전송한다.

set classpath=....mail.jar

java MimeUtilityTest -encode base64 < mypasswd

xxxxxxx

java HttpClient myserver.com

GET /~me/example/passwd HTTP/1.0

Authorization: Basic xxxxxxx

 

^Z

 

BasicAuthTest.java는 HttpURLConnection 클래스 사용시의 인증 정보 처리 예를 보여준다.

import java.net.*;
import java.io.*;
import javax.mail.internet.MimeUtility;

class BasicAuthTest {
    public static void main(String args[]) throws Exception {
        URL url = new URL( args[0] );
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        if (con.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
            BufferedReader stdin
                = new BufferedReader(new InputStreamReader(System.in));
            String realm = con.getHeaderField("WWW-Authenticate");
            int start = realm.indexOf("realm=\"") + 7;
            realm = realm.substring(start, realm.indexOf("\"", start));
            System.out.println(realm + "에 대한 인증 정보를 입력하시오.");
            System.out.print("사용자 ID: ");
            System.out.flush();
            String uid = stdin.readLine();
            System.out.print("암호: ");
            System.out.flush();
            String passwd = stdin.readLine();

            con = (HttpURLConnection) url.openConnection();
            con.setRequestProperty("Authorization", "Basic "
                                   + encodeBase64(uid + ":" + passwd));
        }

        InputStream in = con.getInputStream();
        for(int ch; (ch = in.read()) != -1;)
            System.out.write( ch );
        System.out.flush();
    }

    static String encodeBase64(String str) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        OutputStream encoder
            = MimeUtility.encode(bos, "base64");
        encoder.write(str.getBytes());
        encoder.close();
        return new String(bos.toByteArray());
    }
}

set classpath=....mail.jar

java BasicAuthTest http://myserver.com/~me/example

...

 

 

java.net.Authenticator 추상클래스

 

네트워크 연결에 대한 인증정보( 사용자 이름과 암호 ) 제공

네트워크 연결시 인증이 필요한 경우 URL클래스를 비롯한 자바 내장 패키지에 의해 호출된다.

이 클래스의 하위 클래스로 구현하여 설정한다.

구현된 클래스를 애플릿에서 사용하기 위해서는 디지털 서명이 필요하다.

대개의 경우, 사용자로 부터 인증정보를 입력받도록 구현한다.

 

★ java.net.Authenticator 추상클래스

- Authenticator.setDefault(Authenticator a)

: 프록시 혹은 HTTP 서버가 인증정보를 요구하는 경우 호출될 Authenticator설정. 최초 호출만이 효력을 갖는다.

- PasswordAuthentication requestPasswordAuthentication(InetAddr addr, int port, String protocol, String prompt, String scheme)

: 시스템에 설정된 Authenticator의 getPasswordAuthentication() 메소드를 호출하여 사용자 이름, 암호를 얻어서 반환한다.

- protected PasswordAuthentication getPasswordAuthentication()

: 사용자 이름, 암호를 입력받아 반환하도록 재정의 한다. 제공할 수 없는 경우에는 null반환. 인증 요청 정보는 다음 메소드들로 부터 얻는다.

- protected InetAddress getRequestingSite()

: 인증정보가 요구되는 호스트 주소. 제공되지 않으면 null

- protected int getRequestingPort()

: 인증정보가 요구되는 포트 주소

- protected String getRequestingProtocol()

: 인증정보가 요구되는 프로토콜 이름. "http"등

- protected String getRequestingScheme()

: 인증방식(HTTP의 기본 인증규약의 경우에는 "basic")

- protected String getRequestingPrompt()

: 인증을 요구하는 측에서 제공하는 정보(HTTP의 경우 realm에 해당)

 

★ PasswordAuthentication클래스

- 사용자 이름과 암호의 저장

- new PasswordAuthentication(String userName, char[] password)

- String getUserName()

- char[] getPassword()

 

import java.io.*;
import java.net.*;

class AuthenticatorTest
{   public static void main( String[] args ) 
        throws MalformedURLException, IOException
    {
        Authenticator.setDefault(new MyAuthenticator());

        URL url = new URL(args[0]);
        InputStream in = url.openStream();
        try
        {   for(int ch; (ch = in.read()) != -1;)
                System.out.write( ch );
            System.out.flush();
        } catch( EOFException e ) {}
    }
}

class MyAuthenticator extends Authenticator
{
    protected PasswordAuthentication getPasswordAuthentication()
    {
        try
        {
            System.out.println("getRequestingSite(): " + getRequestingSite());
            System.out.println("getRequestingPort(): " + getRequestingPort());
            System.out.println("getRequestingProtocol(): " + getRequestingProtocol());
            System.out.println("getRequestingScheme(): " + getRequestingScheme());
            System.out.println("getRequestingPrompt(): " + getRequestingPrompt());
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("사용자 ID: ");
            System.out.flush();
            String userName = in.readLine();
            System.out.print("암호: ");
            System.out.flush();
            String password = in.readLine();
            char[] password2 = new char[password.length()];
            password.getChars(0, password.length(), password2, 0);
            return new PasswordAuthentication(userName, password2);
        } catch( IOException ex ) {}
        return null;
    }
}

java AuthenticatorTest http://myserver.com/~me/example