10.2. 웹에서 인증

웹에서 웹 서버는 보통 SSL 및 TLS 또는 서버 인증서를 사용해 사용자에게 인증받는다 - 그러나 사용자가 누구인지를 인증하는 것은 그만큼 쉽지 않다. SSL 과 TLS 는 클라이언트특 인증서를 지원하지만 이들을 실제 사용할 때 많은 현실적인 문제들이 있다 (예, 웹 브라우저는 유일한 사용자 인증서 포맷을 지원하지 않으며 사용자가 이를 설치하기는 어렵다). 자바 및 자바 스크립트를 사용하는 것은 많은 사용자가 이들을 금지하고, 몇몇 방화벽이 이들을 걸러내고 또한 속도가 느려지기 쉽기 때문에 그 특유의 문제를 갖고 있다. 대부분의 경우 모든 사용자에게 플러그인을 설치하도록 요구하는 것 또한 비현실적인데 시스템이 비교적 소수의 사용자들을 위한 인트라넷용이라면 적합할 수도 있다.

인트라넷 애플리케이션을 구축하고 있다면 일반적으로 사용자가 사용하는 인증 시스템만큼은 사용해야 한다. 따라서 Kerberos 에 의존한다면 Kerberos 를 사용하도록 시스템을 설계해라. 관리 기관이 추후 인증 시스템을 변경시킬 수도 있기 (변경시킬 것이기) 때문에 이를 애플리케이션의 나머지 부분과 분리하려고 해라.

많은 방법들은 효과적이지 않으며 또한 충분히 효과적이지 않다. 한가지 접근 방법은 본질적으로 모든 브라우저와 서버에 내장되어 있는 ``기본적인 인증"을 사용하는 것이다. 불행히 기본적인 인증은 패스워드를 평문으로 보내기 때문에 패스워드를 훔치기 쉽게 한다; 기본적인 인증 자체는 실제로 쓸모없는 정보에 대해서만 유용하다. 모든 기본적인 인증 패스워드를 SSL/TLS 연결 (암호화할 수 있다) 내에 감싸서 보호할 수 있지만 이는 성능의 저하를 야기한다. 또한 ``다이제스트 인증"을 사용할 수 있는데 좋은 방법이지만 브라우저가 이를 보편적으로 지원하지 않고 있다. 인증 정보를 사용자가 선택한 URL 내에 저장할 수도 있지만 대부분의 경우 이렇게 하지 않아야 한다 - 이 정보가 다른 사람에게 누설될 수 있는 너무나 많은 방법이 있다 (예, 많은 브라우저에 저장되어 있는 브라우저 히스토리 로그, 프록시의 로그를 통해 누설되거나, 그리고 Referef: 필드를 통해 다른 웹 사이트로 누설될 수도 있다).

따라서 오늘날 웹에서 가장 일반적인 인증 방법은 쿠키를 사용하는 것이다. 쿠키는 실제 이 목적을 위해 설계되지 않았지만 인증에 사용될 수 있다 - 그러나 보안 취약성을 만들기 위해 이들을 사용하는 많은 잘못된 방법이 있기 때문에 주의해라. 쿠키에 대한 더욱 자세하 정보는 이에 대한 예전 스펙과 함께 IETF RFC 2965 를 보라. 쿠키를 사용하기 어떤 브라우저 (예, 마이크로소프트 인터넷 익스플로러 6) 가 프라이버시 프로파일 (서버의 루트 디렉토리에 p3p.xml) 을 가져야 한다고 요구할 수 있음을 주목해라.

어떤 사용자는 쿠키를 받아들이지 않음을 주목해라 따라서 이 방법은 아직까지 다소의 문제를 갖고 있다. 원칙적으로는 이 인증 정보를 HTML 폼의 hidden 필드를 통해 주고받아야 한다 (이는 거의 모든 브라우저가 중요치 않게 이를 지원하기 때문이다). 쿠키를 갖는 것과 같은 동일한 방법을 사용할 것이다 - 단지 데이타를 사용자로부터 서버로 보내기 위해 다른 기술을 사용할 것이다. 물론 이 방법을 구현한다면 이 페이지들이 다른 사람들이 사용할 수 있도록 캐시되지 않음을 보장하는 설정을 포함할 필요가 있다. 그러나 쿠키를 피하는 것이 바람직하다고 저자는 생각하지만 실제로 이러한 다른 방법들은 대개 더욱 더 많은 개발 노력을 필요로 한다. 많은 애플리케이션 개발자들을 위해 이를 대규모로 구현하는 것은 어렵기 때문에 저자는 현재 이러한 방법들을 강조하지 않고 있다. 개발자 또는 사용자에 의해 정확하게 구현될 수 없을 만큼 어려운 방법을 강조하는 대신 꽤 보안적이며 구현하기 쉬운 방법을 기술할 것이다. 그러나 별다른 수고없이 이를 구현할 수 있다면 반드시 폼의 hidden 필드외 암호화된 링크 (예, SSL/TLS) 를 사용해 인증 정보를 전송하는 것을 지원해라.

Fu [2001] 는 제안된 접근 방법과 함께 웹에서의 클라이언트 인증을 논의하고 있다. 이는 대부분의 웹 사이트에 대해 저자가 추천하는 방법이다. 기본적인 개념은 클라이언트 인증을 두 부분 ``로긴 절차 (login procedure)" 와 ``일련의 요청 ( subsequent requests) 으로 나누는 것이다. 로긴 절차에서 서버는 사용자 이름과 패스워드를 요청하고 사용자가 이들을 제공한 후 서버가 ``인증 토큰"을 갖고 응답한다. 일련의 요청에서 클라이언트 (웹 브라우저) 는 서버에 요청과 함께 인증 토큰을 보낸다; 서버는 토큰이 유효한지 확인하고 유효하다면 요청된 서비스를 제공한다. 웹 인증에 대한 다른 좋은 정보 출처는 Seifried [2001] 이다.

10.2.1. 웹에서 인증: 로그인

로긴 절차는 일반적으로 HTML 폼으로 구현된다; 웹 브라우저가 다소의 유용한 액션을 자동적으로 수행할 수 있도록 저자는 필드명으로 ``username" 과 ``password" 를 사용할 것을 제안한다. 반드시 패스워드가 암호화된 연결 (https: 연결을 통해 SSL 또는 TLS 를 사용) 을 통해 전송되도록 해라 - 그렇지 않다면 도청을 통해 패스워드를 수집할 수 있다. 사용자의 스크린을 볼 수 있는 누군가가 패스워드 텍스트를 볼 수 없도록 반드시 모든 패스워드 텍스트 필드는 패스워드로 표시해라.

사용자 이름과 패스워드가 보내질 때 이는 사용자 계정의 테이타베이스에 대해 검사되어야 한다. 이 데이타베이스는 패스워드를 ``평문"으로 저장하지 않아야 하는데 누군가 이 데이타베이스의 복사본을 얻는다면 모든 사람의 패스워드를 갑자기 얻을 수 있다 (사용자는 대개 패스워드를 재사용한다). 어떤 사람은 이를 다루기 위해 crypt() 를 사용하지만 crypt 는 단지 소량의 입력만을 다룰 수 있다. 따라서 저자는 다른 접근 방법을 사용할 것을 추천한다 (이는 저자의 방법으로 Fu [2001] 은 이를 논의하고 있지 않다). 대신 사용자 데이타베이스는 사용자에 대한 사용자 이름, salt 와 패스워드 해시를 저장해야 한다. ''salt" 는 단지 문자들의 임의의 시퀀스로 공격자가 패스워드 데이타베이스를 얻는다 하더라도 패스워드 결정을 더욱 어렵게 하기 위해 사용된다 - 저자는 8 문자의 임의의 시퀀스를 추천한다. 암호학적으로 임의적일 필요는 없으며 단지 다른 사용자들에 대한 값과 다르면 된다. 패스워드 해시는 ``서버 key1", 사용자 패스워드와 salt 를 연결한 후 암호학적으로 보안적인 해시 알고리듬을 사용해서 계산되어야 한다. 서버 key1 은 이 서버에 고유한 비밀 키이다 - 이를 패스워드 데이타베이스와 별도로 보관해라. 서버 key1 을 가진 사람이 패스워드 데이타베이스를 가졌다면 사용자 패스워드를 알아내기 위해 프로그램을 실행시킬 수 있다; 서버 key1 은 기억될 필요가 없기 때문에 길고 복잡한 패스워드일 수 있다. HMAC-SHA-1 또는 HMAC-MD5 가 가장 보안적일 것이다; SHA-1 (대부분의 웹 사이트는 실제 이 알고리듬이 허용하는 공격에 대해 걱정하지 않고 있다) 또는 MD5 (MD5 에 대한 논의를 보라) 를 사용할 수도 있다.

따라서 사용자가 계정을 만들때 패스워드는 패스워드 데이타베이스내에 해시되어 놓여진다. 사용자가 로그인하려고 할때 주장된 패스워드는 해시되어 데이타베이스내의 해시와 비교된다 (이들은 동일해야 한다). 사용자가 패스워드를 변경할 때 예전 및 새로운 패스워드를 모두 타이핑해야 하며 새로운 패스워드는 잘못 타이핑되지 않았음을 확인하기 위해 두번 타이핑해야 한다; 또한 패스워드 문자들중 어느 문자도 스크린상에서 볼 수 없도록 해라.

디폴트로 쿠키를 사용하는 클라이언트의 웹 브라우저에 패스워드 자체를 저장하지 마라 - 사용자들은 때때로 공유되는 클라이언트를 사용할 수도 있다 (가령 커피숍). 원한다면 사용자에게 브라우저에서 ``패스워드 저장하기" 옵션을 줄 수 있지만 이 경우 반드시 패스워드가 ``보안적인" 연결을 통해서만 전송되도록 설정하고 사용자가 명확하게 이를 요청하도록 해라 (디폴트로 이를 하지는 마라).

반드시 캐시되지 않는 페이지를 표시해라 그렇지 않다면 서버가 그 페이지를 사용자에게 다시 제공할 것이다.

일단 사용자가 성공적으로 로그인하면 서버는 쿠키내의 ``인증 토큰"을 클라이언트에 전송할 필요가 있다. 이는 다음에 기술된다.

10.2.2. 웹에서 인증: 일련의 행동

일단 사용자가 로그인하면 서버는 클라이언트에 인증 토큰을 갖고 있는 쿠키를 되돌려준다. 제안된 토큰은 다음과 같을 것이다:

  exp=t&data=s&digest=m

t 는 토큰의 만료 시간 (가령 몇 시간) 이고, data 는 사용자 이름 또는 세션 id 들이고 digest 는 keyed digest 이다. ``data" 의 필드명을 더욱 설명적인 사용자 이름 또는 세션 id 로 자유롭게 변경할 수 있다. Keyed digest 는 만료 시간과 data 를 연결한 것의 암호학적인 해시이다. 데이타에 한 필드 이상 (예, 사용자 이름과 세션 id 둘) 을 갖는다면 반드시 digest 가 인증하려는 필드명과 모든 필드의 data 모두를 사용하도록 해라; 이들을 필드 data 값 어디에도 있을 수 없는 패턴 (예, ``%%", ``+" 또는 ``&") 을 이용해 연결해라. Keyed digest 는 별개의 서버 키 (key2) 를 사용하는 HMAC-MD5 또는 HMAC-SHA1 을 사용해야 한다. 이 key2 가 손상된다면 누구라도 서버에 인증받을 수 있으며 key2 를 변경하는 것이 쉽다 - 변경한다면 이는 단순히 현재 ``로그인 해 있는" 사용자에게 재인증받도록 요구할 것이다. 더욱 자세한 사항은 Fu [2001] 을 보라.

그때부터 서버는 이 인증 토큰의 만료 시간과 digest 를 검사해 일치하는 경우에만 데이타를 제공해야 한다. 토큰이 없다면 사용자 로긴 페이지 (성공적인 로긴시 어디로 가는 지를 보이는 숨겨진 폼 필드를 갖고 있다) 로 다시 응답할 것이다 .

인증 토큰에 세션 id 를 포함하고 있다면 접근을 더욱 제한할 수 있다. 서버는 사용자가 주어진 세션에서 어떤 패이지를 보았는지 추적할 수 있으며 단지 적절한 페이지에 대한 접근만 허용할 수 있다 (예, 이러한 페이지들에서 직접적으로 링크되어 있는 페이지들). 예를 들어 사용자가 foo.html 에 접근할 수 있고 foo.html 페이지가 자원 bar1.jpg 와 bar2.png 에 대한 포인터를 갖고 있다면 bar4.cgi 에 대한 접근은 거절될 수 있다. 세션을 종료할 수도 있는데 이는 인증 정보가 유효한 경우에만 해라 (그렇지 않다면 공격자가 다른 사용자에 대해 서비스 부인 공격을 야기할 수도 있게 한다). 이는 공격자가 세션을 성공적으로 가로챈다 하더라도 어느 정도 공격자가 갖는 접근을 제한할 수 있다. 그러나 시간과 인증 토큰을 갖고 있는 공격자는 정상적인 사용자와 같이 링크를 따라 페이지들을 볼 수 있을 것이다.

한가지 결정해야 하는 것은 인증 토큰 및/또는 data 가 보안적인 연결(예, SSL) 을 통해 보내져야 하는 지 또는 아닌지이다. 인증 토큰을 평문으로 (비보안적으로) 전송한다면 토큰을 가로챈 누군가는 만료 시간까지 사용자가 할 수 있는 모든 것을 할 수 있다. 또한 데이타를 암호화되지 않은 링크를 통해 전송할 때 공격자가 눈에 띄지 않게 변경할 수 있는 위험도 있다; 누군가가 전송중에 데이타를 변경할 수도 있다고 걱정한다면 전송되어 지는 데이타를 인증할 필요가 있다. 암호화 자체는 인증을 보장하지 않지만 변조를 더욱 쉽게 탐지할 수 있게 하며 일반적인 라이브러리는 TLS/SSL 연결에서 암호화와 인증 모두를 지원할 수 있다. 일반적으로 메시지를 암호화한다면 또한 이를 인증해야 한다. 필요한 것이 다르다면 한가지 대안은 두개의 인증 토큰을 생성하는 것이다 - 한개는 중요한 작업을 위해 ``보안적인" 연결에만 사용되고 반면 다른 한개는 덜 중요한 작업에 사용된다. 단지 보안적인 연결 (일반적으로 암호화된 SSL/TLS 연결) 들만이 사용되도록 ``보안적인" 연결에 사용되는 토큰은 반드시 표시를 해라. 사용자들이 실제로 다르지 않다면 인증 토큰은 ``data" 를 전적으로 생략할 수 있다.

이 인증 토큰을 갖는 페이지들이 반드시 캐시되지 않도록 해라. 또한 다른 적당한 스킴도 또한 있다; 여기서의 목적은 적어도 한가지 보안적인 해결 방법을 제공하는 데 있으며 많은 변형된 방법들도 가능하다.

10.2.3. 웹에서 인증: 로그아웃

사용자에게 ``로그 아웃" 할 수 있는 메카니즘을 늘 제공해야 한다 - 이는 도서관에서와 같이 많은 사람들이 브라우저를 공유해서 사용하는 경우 특히 유용하다. ``logout" 루틴이 하는 일은 간단하다 - 클라이언트의 인증 토큰을 단지 설정해제하는 것이다.