Http authentication: Difference between revisions

From 탱이의 잡동사니
Jump to navigation Jump to search
No edit summary
 
(7 intermediate revisions by the same user not shown)
Line 3: Line 3:


== Basic ==
== Basic ==
HTTP 에서 사용하는 인증 방법은 다음과 같다.
HTTP 에서 사용할 수 있는 인증 방법은 다음과 같다.


* Anonymous(익명)
* Anonymous(익명)
* BASIC 인증
* BASIC authorization
* DIGEST 인증
* DIGEST authorization
* SSL 클라이언트 인증
* SSL client authorization
* 폼 베이스 인증
* Form base authorization
* OAuth
* OAuth


== Anonymous ==
== Anonymous ==
인증정보를 포함하지 않는 요청도 인증 방식에 포함된다. 리소스에 대해 모든 엑세스 권한을 부여한다.
== Basic authentication ==
Basic authentication(BA) 인증. 클라이언트에 사용자 이름과 암호를 Base64 로 된 문자열을 요청한다. 간편하며 널리 쓰이지만, 패킷 도청에 매우 취약하다.
=== Feature ===
* BA인증은 전송 단계에서 아무런 암호화 보안을 제공하지 않는다. 단순히 Base64로 인코딩을 할 뿐이며, 어떠한 암호화나 해쉬화가 되지 않는다. 이 때문에 자주 HTTP에서는 이를 다른 암호화 기술과 함께 혼용하여 사용한다.
* Base64로 인코딩된 값은 쉽게 디코딩이 가능하다. 비밀번호가 그대로 노출된다. 때문에 쉽게 사용자 정보를 알아내어 악용할 수 있다.
* BA인증 필드는 HTTP 요청 헤더에 포함되기 때문에, 필요한 경우, WEB 브라우저 자체에서 인증정보(username/password)를 캐시로 저장할 수 있다. 캐시되는 기간과 정책은 각각의 브라우저마다 다르다.
* HTTP 에서는 웹서버의 Log out 메소드를 지원하지 않는다. 하지만 보안 캐시를 삭제하는 몇가지 방법들이 있다. 그 중 한가지 방법으로 사용자를 다른 URL 로 redirect 하여 보안 정보를 더 이상 사용할 수 없는 정보로 업데이트하게끔 유도하는 것이다.
* BA 인증과 관련한 캐싱/기간/정책 등은 브라우저마다 다를 수 있다.
* 프록시나 중개자가 개입하는 경우, 정상적인 동작을 보장하지 않는다.
* 가짜 서버의 위장에 취약하다.
=== Protocol ===
다음과 같은 내용으로 프로토콜이 진행된다.
<pre>
- Client 는 서버로
</pre>
* Server side
* Client Side
=== Example ===
<source lang=c>
// main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdbool.h>
#include <evhtp.h>
#define DEF_BASIC_REALM "pchero21.com mailservice"  // basic realm info
/**
\brief reply unauth error with realm info.
*/
void reply_unauth_error(evhtp_request_t* r)
{
    // set realm info
    evhtp_headers_add_header(r->headers_out, evhtp_header_new("WWW-Authenticate", "Basic realm=" DEF_BASIC_REALM, 0, 0));
    evhtp_headers_add_header(r->headers_out, evhtp_header_new("Content-Length", "0", 0, 0));
    evhtp_send_reply(r, EVHTP_RES_UNAUTH);
    return;
}
bool check_basic_auth(evhtp_request_t* r)
{
    evhtp_connection_t* conn;
    const char* auth_hdr;
   
    if(r == NULL) {
        fprintf(stderr, "Wrong input parameter.\n");
        return false;
    }
   
    conn = evhtp_request_get_connection(r);
    if(conn == NULL) {
        fprintf(stderr, "Could not get connection info.\n");
        return false;
    }
   
    if(conn->request->headers_in == NULL) {
        fprintf(stderr, "Could not get correct connection info.\n");
        return false;
    }
   
    // Get Base64 encoded Authorization info
    auth_hdr = evhtp_kv_find(conn->request->headers_in, "Authorization");
    if(auth_hdr == NULL) {
        fprintf(stderr, "Could not get auth info.\n");
        return false;
    }
   
    // Authorization: Basic SOME_BASE_64_ENCODED_STRING
    fprintf(stdout, "Requested authorization info. auth_hdr[%s]\n", auth_hdr);
   
    return true;
}
void testcb(evhtp_request_t *req, void *a)
{
    const char *str = a;
    int ret;
    printf("test callback.\n");
    ret = check_basic_auth(req);
    if(ret == false) {
        reply_unauth_error(req);
        return;
    }
   
    evbuffer_add_printf(req->buffer_out, "%s", str);
    evhtp_send_reply(req, EVHTP_RES_OK);
}
int main(int argc, char** argv)
{
    evbase_t *evbase    = event_base_new();
    evhtp_t *htp        = evhtp_new(evbase, NULL);
   
    evhtp_set_cb(htp, "/simple/", testcb, "simple");
    evhtp_bind_socket(htp, "0.0.0.0", 8081, 1024);
   
    event_base_loop(evbase, 0);
   
    evhtp_unbind_socket(htp);
    evhtp_free(htp);
    event_base_free(evbase);
   
    return 0;
}
</source>
Sample
<pre>
$ ./main &
...
$ curl -vX GET http://127.0.0.1:8081/simple/ --user pchero:1234
* Hostname was NOT found in DNS cache
*  Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
* Server auth using Basic with user 'pchero'
> GET /simple/ HTTP/1.1
> Authorization: Basic cGNoZXJvOjEyMzQ=
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:8081
> Accept: */*
>
test callback.
Requested authorization info. auth_hdr[Basic cGNoZXJvOjEyMzQ=]
< HTTP/1.1 200 OK
< Content-Length: 6
< Content-Type: text/plain
<
* Connection #0 to host 127.0.0.1 left intact
--------------------------------------------------------------
$ curl -vX GET http://127.0.0.1:8081/simple/
* Hostname was NOT found in DNS cache
*  Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
> GET /simple/ HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:8081
> Accept: */*
>
test callback.
Could not get auth info.
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm=pchero21.com mailservice
< Content-Length: 0
< Content-Type: text/plain
<
* Connection #0 to host 127.0.0.1 left intact
</pre>


== See also ==
== See also ==
* http://sonim1.tistory.com/100 - HTTP 를 이용한 인증방식 - BASIC, DIGEST, SSL, FORM
* http://sonim1.tistory.com/100 - HTTP 를 이용한 인증방식 - BASIC, DIGEST, SSL, FORM
* https://en.wikipedia.org/wiki/Basic_access_authentication - Basic access authentication
* http://iloveulhj.github.io/posts/http/http-basic-auth.html - [HTTP] 기본 인증
* http://behonestar.tistory.com/35 - HTTP Digest 인증
* http://behonestar.tistory.com/35 - HTTP Digest 인증


[[category:http]]
[[category:http]]

Latest revision as of 11:27, 10 August 2016

Overview

http authentication 내용 정리.

Basic

HTTP 에서 사용할 수 있는 인증 방법은 다음과 같다.

  • Anonymous(익명)
  • BASIC authorization
  • DIGEST authorization
  • SSL client authorization
  • Form base authorization
  • OAuth

Anonymous

인증정보를 포함하지 않는 요청도 인증 방식에 포함된다. 리소스에 대해 모든 엑세스 권한을 부여한다.

Basic authentication

Basic authentication(BA) 인증. 클라이언트에 사용자 이름과 암호를 Base64 로 된 문자열을 요청한다. 간편하며 널리 쓰이지만, 패킷 도청에 매우 취약하다.

Feature

  • BA인증은 전송 단계에서 아무런 암호화 보안을 제공하지 않는다. 단순히 Base64로 인코딩을 할 뿐이며, 어떠한 암호화나 해쉬화가 되지 않는다. 이 때문에 자주 HTTP에서는 이를 다른 암호화 기술과 함께 혼용하여 사용한다.
  • Base64로 인코딩된 값은 쉽게 디코딩이 가능하다. 비밀번호가 그대로 노출된다. 때문에 쉽게 사용자 정보를 알아내어 악용할 수 있다.
  • BA인증 필드는 HTTP 요청 헤더에 포함되기 때문에, 필요한 경우, WEB 브라우저 자체에서 인증정보(username/password)를 캐시로 저장할 수 있다. 캐시되는 기간과 정책은 각각의 브라우저마다 다르다.
  • HTTP 에서는 웹서버의 Log out 메소드를 지원하지 않는다. 하지만 보안 캐시를 삭제하는 몇가지 방법들이 있다. 그 중 한가지 방법으로 사용자를 다른 URL 로 redirect 하여 보안 정보를 더 이상 사용할 수 없는 정보로 업데이트하게끔 유도하는 것이다.
  • BA 인증과 관련한 캐싱/기간/정책 등은 브라우저마다 다를 수 있다.
  • 프록시나 중개자가 개입하는 경우, 정상적인 동작을 보장하지 않는다.
  • 가짜 서버의 위장에 취약하다.

Protocol

다음과 같은 내용으로 프로토콜이 진행된다.

- Client 는 서버로 
  • Server side


  • Client Side

Example

<source lang=c> // main.c

  1. define _GNU_SOURCE
  1. include <stdio.h>
  2. include <stdbool.h>
  3. include <evhtp.h>
  1. define DEF_BASIC_REALM "pchero21.com mailservice" // basic realm info

/**

\brief reply unauth error with realm info.
*/

void reply_unauth_error(evhtp_request_t* r) {

   // set realm info
   evhtp_headers_add_header(r->headers_out, evhtp_header_new("WWW-Authenticate", "Basic realm=" DEF_BASIC_REALM, 0, 0));
   evhtp_headers_add_header(r->headers_out, evhtp_header_new("Content-Length", "0", 0, 0));
   evhtp_send_reply(r, EVHTP_RES_UNAUTH);
   return;

}

bool check_basic_auth(evhtp_request_t* r) {

   evhtp_connection_t* conn;
   const char* auth_hdr;
   
   if(r == NULL) {
       fprintf(stderr, "Wrong input parameter.\n");
       return false;
   }
   
   conn = evhtp_request_get_connection(r);
   if(conn == NULL) {
       fprintf(stderr, "Could not get connection info.\n");
       return false;
   }
   
   if(conn->request->headers_in == NULL) {
       fprintf(stderr, "Could not get correct connection info.\n");
       return false;
   }
   
   // Get Base64 encoded Authorization info
   auth_hdr = evhtp_kv_find(conn->request->headers_in, "Authorization");
   if(auth_hdr == NULL) {
       fprintf(stderr, "Could not get auth info.\n");
       return false;
   }
   
   // Authorization: Basic SOME_BASE_64_ENCODED_STRING
   fprintf(stdout, "Requested authorization info. auth_hdr[%s]\n", auth_hdr);
   
   return true;

}

void testcb(evhtp_request_t *req, void *a) {

   const char *str = a;
   int ret;
   printf("test callback.\n");
   ret = check_basic_auth(req);
   if(ret == false) {
       reply_unauth_error(req);
       return;
   }
   
   evbuffer_add_printf(req->buffer_out, "%s", str);
   evhtp_send_reply(req, EVHTP_RES_OK);

}

int main(int argc, char** argv) {

   evbase_t *evbase    = event_base_new();
   evhtp_t *htp        = evhtp_new(evbase, NULL);
   
   evhtp_set_cb(htp, "/simple/", testcb, "simple");
   evhtp_bind_socket(htp, "0.0.0.0", 8081, 1024);
   
   event_base_loop(evbase, 0);
   
   evhtp_unbind_socket(htp);
   evhtp_free(htp);
   event_base_free(evbase);
   
   return 0;

} </source>

Sample

$ ./main &
...

$ curl -vX GET http://127.0.0.1:8081/simple/ --user pchero:1234
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
* Server auth using Basic with user 'pchero'
> GET /simple/ HTTP/1.1
> Authorization: Basic cGNoZXJvOjEyMzQ=
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:8081
> Accept: */*
> 

test callback.
Requested authorization info. auth_hdr[Basic cGNoZXJvOjEyMzQ=]

< HTTP/1.1 200 OK
< Content-Length: 6
< Content-Type: text/plain
< 
* Connection #0 to host 127.0.0.1 left intact

--------------------------------------------------------------

$ curl -vX GET http://127.0.0.1:8081/simple/
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
> GET /simple/ HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:8081
> Accept: */*
> 

test callback.
Could not get auth info.

< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: Basic realm=pchero21.com mailservice
< Content-Length: 0
< Content-Type: text/plain
< 
* Connection #0 to host 127.0.0.1 left intact

See also