PHP 매뉴얼
이전 |  | 다음

# 16. 장. PHP로 HTTP 인증하기

PHP를 이용한 HTTP 인증은 아파치 모듈로 실행할때만 사용할 수 있으며, CGI 버전에서는 사용할 수 없습니다. 아파치 모듈에서 PHP 스크립트가 header() 함수를 이용하여 "인증 요구" 메세지를 클라이언트 브라우저에 전송함으로써, 사용자명/패스워드 입력창을 띄울 수 있습니다. 사용자가 사용자명과 패스워드를 입력하면, PHP 스크립트의 URL이 다시 호출하고, 예약 정의 변수 `PHP_AUTH_USER`, `PHP_AUTH_PW`, `AUTH_TYPE`에 사용자명, 패스워드, 인증 형식이 들어갑니다. 이 예약 정의 변수들은 $_SERVER와 `$HTTP_SERVER_VARS` 배열로 확인할 수 있습니다. 현재는 "Basic" 인증만을 지원합니다. 자세한 정보는 header() 함수를 참고하십시오.

> PHP 버전 주의: $_SERVER 등의 자동 전역 변수는 PHP 4.1.0부터 사용할 수 있습니다. `$HTTP_SERVER_VARS`는 PHP 3부터 사용할 수 있습니다.

다음은 페이지에 대해 클라이언트 인증을 강제하는 예제 스크립트입니다:

예 16-1. HTTP 인증 예제

`<?php if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); echo '사용자가 취소 버튼을 눌렀을 때 전송되는 텍스트'; exit; } else { echo "<p>안녕하세요, {$_SERVER['PHP_AUTH_USER']}.</p>"; echo "<p>{$_SERVER['PHP_AUTH_PW']}를 패스워드로 접속했습니다.</p>"; } ?>`

> 호환성 주의: HTTP 헤더열을 코딩할때는 주의를 기울이십시오. 모든 클라이언트에 대해 최대의 호환성을 보장받기 위해서는, 키워드 "Basic"은 대문자 "B"로 쓰여져야하고, 렐름 메세지는 이중 인용 부호(")로 감싸져야하며, HTTP/1.0 401 헤더열에서 401 코드는 정확히 하나의 스페이스를 가져야합니다.

위 예제와 같이 단순히 `PHP_AUTH_USER`와 `PHP_AUTH_PW`를 출력하는 대신, 유저네임과 패스워드를 확인해서 인증을 할 수 있습니다. 데이터베이스에 요구를 하거나, dbm 파일에서 유저를 찾아낼 수 있습니다.

인터넷 익스플로러 브라우저의 버그에 주의하십시오. 헤더의 순서에 매우 까다롭습니다. WWW-Authenticate 헤더를 `HTTP/1.0 401` 헤더 전에 전송하는 것이 현재 사용 가능한 방법입니다.

PHP 4.3.0부터, 전통적인 외부 메카니즘을 통해서 인증된 페이지의 패스워드를 누출하는 스크립트의 작성을 방지하기 위해서, 각각의 페이지에 대한 외부 인증과 안전 모드가 활성화되었을때, PHP_AUTH 변수를 설정하지 않습니다. 대신, 외부 인증 유저를 확인하기 위해서 `REMOTE_USER`를 사용할 수 있습니다. 그러므로, `$_SERVER['REMOTE_USER']`를 사용하십시오.

> 설정 주의: PHP는 외부 인증을 검증할 때 `AuthType` 지시어의 존재를 확인합니다.

이 방식은 비인증 URL을 조작해서 같은 서버의 인증 URL의 패스워드를 훔치는 것은 방지할 수 없다는 점에 주의하십시오.

넷스케이프 네비게이터와 인터넷 익스플로러는 서버 응답 401을 받았을 때, 로컬 브라우저창의 인증 캐쉬를 클리어합니다. 이것은 강제로 유저네임과 패스워드를 재입력하게 함으로써, 사용자를 '로그 아웃'하는 효과를 가집니다. 몇몇 사람들은 이것을 "시간 제한" 로그인이나, "로그 아웃" 버튼을 제공을 통해 사용합니다.

예 16-2. 새 이름/패스워드를 강제하는 HTTP 인증 예제

`<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="테스트 인증 시스템"');
header('HTTP/1.0 401 Unauthorized');
echo "이 자원에 접근하기 위해서는 유효한 로그인 ID와 패스워드를 입력해야 합니다.\n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
}
else {
echo "<p>어서오십시오: {$_SERVER['PHP_AUTH_USER']}<br />";
echo "이전: {$_REQUEST['OldAuth']}";
echo "<form action='{$_SERVER['PHP_SELF']}' METHOD='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value='{$_SERVER['PHP_AUTH_USER']}' />\n";
echo "<input type='submit' value='재인증' />\n";
echo "</form></p>\n";
}
?>`

이 행동은 HTTP Basic 인증 표준에 필요하지 않기 때문에, 이것에 의존해서는 안됩니다. Lynx로 테스트 했을때, Lynx는 401 서버 응답에 인증 정보를 클리어하지 않기에, 이전의 인증 정보를 그대로 이용해서 자원을 얻으려고 시도합니다. 대신, 사용자가 '_' 키를 누름으로써 인증 정보를 삭제할 수 있습니다.

PHP 4.3.3까지, 마이크로소프트의 IIS 서버를 CGI 버전의 PHP로 사용할 때, IIS의 제약으로 인하여 HTTP 인증은 작동하지 않습니다. PHP 4.3.3 이상에서 작동하게 하려면, IIS 환경 설정 "디렉토리 보안"을 수정해야 합니다. "수정"을 클릭하고, "익명 접근"만을 체크하고, 다른 모든 필드는 체크를 해제하십시오.

IIS 모듈(ISAPI)를 사용할 때 다른 제약은, `PHP_AUTH_*` 변수를 사용할 수 없는 대신, `HTTP_AUTHORIZATION` 변수를 사용하게 됩니다. 즉, 다음의 코드를 고려해야합니다. `list($user, $pw) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));`

> IIS 주의:: IIS에서 HTTP 인증을 작동하게 하려면, PHP 지시자 cgi.rfc2616_headers를 `0`(초기값)으로 설정해야 합니다.

> 참고: 안전 모드에서는 스크립트의 uid가 `WWW-Authenticate` 헤더의 `realm` 부분에 추가됩니다.

이전 | 처음으로 | 다음
기능 | 위로 | 쿠키