PHP 로그인 스크립트에 어떤 모범 사례를 적용해야합니까?


27

클라이언트 웹 사이트의 로그인 스크립트를 다시 작성하여 더 안전하게 만들고 싶습니다. 이 모범 사례를 구현할 수있는 모범 사례를 알고 싶습니다. 암호로 보호 된 제어판은 풍부하지만 코드 작성, 속도 및 보안 측면에서 모범 사례를 암시하는 것으로 거의 보이지 않습니다.

PHP와 MYSQL 데이터베이스를 사용할 것입니다.

나는 md5를 사용했지만 sha256 또는 sha512가 더 좋을 것입니다 (보안 해시 및 소금과 함께).

일부 로그인 스크립트는 세션 또는 사용자 에이전트 전체에서 IP 주소를 기록하지만 프록시 서버와 호환되지 않기 때문에 피하고 싶습니다.

또한 PHP 5에서 세션을 사용하는 모범 사례 (마지막으로 읽은 시간은 PHP 4였습니다)에 약간의 도움이되므로 일부 모범 사례가 도움이 될 것입니다.

감사.


1
codereview.SE에서 스크립트를 던져보세요!
Chris

@Chris CodeReview는 코드의 명확성 등에 도움을줍니다. 당신은 확실히 보안을 위해 그들에게 가지 않아야합니다. 어떤 것이 든, 그들은 거의 항상 "자신의 롤링"을하지 말라고 생각할 것입니다. 이것은 SE의 어떤 프로그래밍 커뮤니티에서든지 기본적으로 같은 대답입니다.
Alternatex

답변:


21

가장 좋은 생각은 바퀴를 재발 명하지 않는 것입니다. 그러나 PHP 세계에서는 이미 그렇게하는 고품질 구성 요소를 찾는 것이 어려울 수 있음을 이해합니다 (심지어 프레임 워크가 그러한 것들을 구현하고 구현이 이미 테스트되고 견고하며 코드 검토 등인지 확신합니다). )

어떤 이유로 프레임 워크를 사용할 수없는 경우 다음과 같은 제안 사항이 있습니다.

보안 관련 제안

  • 가능하면 PBKDF2 또는 Bcrypt를 사용하십시오 . 그것은 끝났습니다.

    이론적 근거 : 두 알고리즘 모두 해싱 프로세스를 임의로 느리게 만들 수 있습니다. 이는 비밀번호를 해시 할 때 원하는 것입니다. 이상적으로는 동일한 하드웨어에서 시간이 지남에 따라 프로세스 속도가 느려지고 느리고 새롭고 빠른 하드웨어가 릴리스되도록 매개 변수를 조정해야합니다.

  • 할 수 없다면 최소한 MD5 / SHA1을 사용하지 마십시오. 못. 잊어 버려 . 예를 들어 SHA512를 대신 사용하십시오. 소금도 사용하십시오.

    근거 : MD5와 SHA1이 너무 빠릅니다. 공격자가 해시가 포함 된 데이터베이스에 액세스 할 수 있고 강력한 컴퓨터가있는 경우 (특히 강력하지 않은) 강력한 암호를 사용하는 것이 빠르고 쉽습니다. 소금이 없으면 공격자가 실제 비밀번호를 발견 할 가능성이 높아집니다 (비밀번호를 다른 곳에서 재사용하면 추가 피해를 입을 수 있음).

  • PHP 5.5.0 이상에서 사용 password_hash하고 password_verify.

    이론적 근거 : 프레임 워크에서 제공하는 함수를 호출하는 것이 쉬우므로 실수 할 위험이 줄어 듭니다. 이 두 함수를 사용하면 해시와 같은 다른 매개 변수에 대해 생각할 필요가 없습니다. 첫 번째 함수는 단일 문자열을 반환 한 다음 데이터베이스에 저장할 수 있습니다. 두 번째 함수는이 문자열을 비밀번호 확인에 사용합니다.

  • 무차별적인 힘으로부터 자신을 보호하십시오 . 0.01 초 전에 다른 비밀번호를 이미 제출했을 때 사용자가 잘못된 비밀번호를 제출 한 경우이를 차단해야합니다. 인간은 빨리 타이핑 할 수 있지만 아마도 그렇게 빠를 수는 없습니다 .

    또 다른 보호는 시간당 실패 제한을 설정하는 것입니다. 사용자가 한 시간에 3600 개의 잘못된 암호 (초당 1 개의 암호)를 제출 한 경우 이것이 합법적 인 사용자라고 믿기가 어렵습니다.

    이론적 근거 : 암호가 안전하지 않은 방식으로 해시되면 무차별 대입이 매우 효과적 일 수 있습니다. 암호가 안전하게 저장 되어도 여전히 서버 리소스와 네트워크 대역폭이 낭비되어 합법적 인 사용자의 성능이 저하됩니다. 무차별 힘 탐지는 개발하기가 쉽지 않고 올바르게 작동하기는하지만 작은 시스템을 제외하고는 그만한 가치가 있습니다.

  • 사용자에게 4 주마다 비밀번호를 변경하도록 요청하지 마십시오. 이는 포스트잇 기반 보안을 장려하기 때문에 매우 성가 시며 보안을 저하시킵니다 .

    이론적 근거 : n 주 마다 암호를 강제로 변경 하여 시스템을 무차별 적으로 보호 한다는 생각 은 잘못되었습니다. 무차별 대입 공격은 일반적으로 몇 초, 몇 분, 몇 시간 또는 몇 일 내에 성공하므로 월별 비밀번호 변경은 무의미합니다. 반면에, 사용자는 암호를 기억하기가 어렵습니다. 또한 변경해야 할 경우 매우 간단한 비밀번호를 사용하거나 포스트잇에 비밀번호를 기록합니다.

  • 항상 모든 것을 감사하십시오. 로그온은 저장하지만 감사 로그에는 암호를 저장하지 마십시오. 감사 로그를 수정할 수 없는지 확인하십시오 (예 : 끝에 데이터를 추가 할 수 있지만 기존 데이터는 수정할 수 없음). 감사 로그가 정기적으로 백업되는지 확인하십시오. 이상적으로는 매우 제한적인 액세스 권한을 가진 전용 서버에 로그를 저장하는 것이 가장 좋습니다. 다른 서버가 해킹 된 경우 공격자는 로그를 지워서 자신의 존재 (및 공격 중에 발생한 경로)를 숨길 수 없습니다.

  • 사용자가 요청하지 않는 한 쿠키에 사용자 자격 증명을 기억하지 마십시오 (인적 오류를 피하려면 기본적으로“기억”확인란의 선택을 취소해야합니다).

사용 편의성 제안

  • 대부분의 브라우저가 이미이 기능인 경우에도 원하는 경우 사용자가 비밀번호를 기억하도록하십시오 .
  • 사용자 이름과 비밀번호를 요청하는 대신 Google 접근 방식을 사용하지 마십시오. 사용자는 때때로 비밀번호 만 요청 하고 사용자 이름은 이미에 표시되어 있습니다 <span/>. 이 경우 브라우저는 비밀번호 필드를 채울 수 없으며 (적어도 Firefox는이를 수행 할 수 없음) 강제로 로그 오프 한 다음 브라우저로 채워진 일반 양식으로 로그온해야합니다.
  • 로그온에 JavaScript 가능 팝업 을 사용하지 마십시오 . 브라우저의 암호 기억 기능을 손상시킵니다 (모든 경우에 짜증납니다).
  • 사용자 가 자신의 사용자 이름 또는 메일 주소를 입력 하도록합니다 . 등록 할 때 입력하려는 사용자 이름이 이미 사용되므로 새 이름을 만들어야합니다. 나는이 이름을 두 시간 안에 잊을 수있는 모든 기회를가집니다.
  • 항상 로그온 양식 근처에 "암호를 잊어 버렸습니다" 기능에 대한 링크를 유지 하십시오 . 사용자가 로그온에 실패한 경우에만 표시하지 마십시오. 비밀번호를 전혀 기억하지 못하는 사용자는 "비밀번호를 잊어 버렸습니다"링크를 보려면 잘못된 비밀번호를 제출해야한다는 것을 전혀 모릅니다.
  • post-it로 보안을 사용하지 마십시오 .
  • 암호를 약하게 만들기 위해 암호와 관련된 어리석은 규칙을 만들지 마십시오 . 예 : "비밀번호는 소문자로 시작해야합니다."; "비밀번호는 공백을 포함 할 수 없습니다."

bcrypt를 발견하지 마십시오. 그것을 추천하는 당신의 추론은 무엇입니까? 왜 md5 / sha1이 아닌가? 나머지 제안에 감사드립니다!
baritoneuk

추론은 간단합니다. bcrypt자격을 갖춘 사람들이 수행합니다. 또한 테스트, 검토 등을 수행하므로 동일한 것을 직접 구현할 이유가 없습니다. 웹 사이트를위한 자체 암호화 알고리즘을 만드는 것과 같습니다. * "md5 / sha1이 아닌 이유": 예 : en.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko

5
bcrypt는 느리고 전문가가 언급 한대로. md5는 암호화가 아닌 해싱 알고리즘으로 동일하지 않습니다. 파일을 빨리 해싱하는 것이 좋으며 md5가 여기에 사용됩니다 ... 암호를 너무 빨리 할 필요는 없습니다 .bcrypt가 여기에 도움이 될 수 있습니다. 이유는 이것이 암호 알고리즘이 "느리게"있을 때 무차별 대입이 더 어려워 진다고 말합니다.
Chris

2
@ baritoneuk : 최소는 시원합니다. 그러나 최대 길이, 영숫자가 아닌 문자 등의 제한이있는 사이트 수를 계산할 수는 없습니다 . 어쨌든 암호를 해시하려는 경우 어리둥절합니다. , 그들은 단지 데이터베이스에 분명하게 저장하고 있습니다.
Carson63000

1
@Brian Ortiz : 항상 그런 것은 아닙니다. 때로는 한계를 설정하는 것이 좋습니다. 그렇지 않으면 응용 프로그램이 어떤 길이로 작동하는지 테스트합니까? 방법? 테스트하지 않으면 작동하는지 어떻게 확인할 수 있습니까? 대신 100과 같이 합리적인 값으로 제한을 설정하면 100 자 암호를 쉽게 테스트 할 수 있습니다.
Arseni Mourzenko 오전

6
  1. 사이트는 HTTPS를 사용해야 합니다. 로그인 페이지를 제시하거나 암호화되지 않은 연결의 로그인을 수락해서는 안됩니다.
  2. 쿠키는 제한해야 HTTP 전용 당신이 HTTPS를 사용하는 경우 연결을 보호하기 위해 제한 될 수있다.
  3. 로그인 프로세스는 2 초 이상 걸리지 않아야합니다 (2 초가 너무 길다고 생각되면 1). 암호를 저장하고 확인할 때는 안전한 해시를 사용하고 추측하기 어려운 소금을 사용하십시오. bcrypt가능하면 사용하십시오 . 그렇지 않으면 다른 종류의 반복 해시를 사용하십시오.
  4. 결코 지금 과 같은 기능을 사용하여 필요로하는 방식으로 데이터베이스 쿼리를 구성하지 않습니다 mysql_real_escape_string. 문자열 연결을 사용하여 쿼리를 작성하지 마십시오. 준비되고 매개 변수화 된 쿼리를 사용하십시오. 전부는 아니지만 대부분의 PHP 용 DB 드라이버가이를 지원합니다. 당신이 그것을 할 방법을 모르는 경우 어떻게하는 데 시간이 학습을 보내고 prepare, bindexecute사용 어떤 DB를 사용하고 있습니다. 그건SQL 주입으로부터 자신을 보호 할 수 유일한 방법입니다. PDO가이를 지원합니다.
  5. 사용자가 이메일에 사용하는 것과 동일한 비밀번호를 사용 하지 않도록 권장하십시오 . 사이트가 손상되고 두 곳에서 동일한 비밀번호를 사용하는 경우 누군가가 이메일을 도용 할 수 있음을 상기시킵니다.

공용 WiFi 네트워크를 통해 점점 더 많은 트래픽이 발생하므로 HTTPS의 경우 +1입니다. 그러나 나는 3 점에 동의하지 않는다. 2 초는 사용자 관점에서 너무 길다. 0.5 초 특히 다른 안티-브 루트 포스 기술을 사용하는 경우에는 문제가 없습니다.
Arseni Mourzenko

포인트 번호 4에서 혼란 스러워요. mysql_real_escape_string으로 데이터를 이스케이프 처리하는 방법을 어떻게 피할 수 있습니까? 사용자가 제출 한 모든 데이터를 신뢰할 수 있고 적절하게 필터링해서는 안됩니다.
chrisw

@ chrisw : 예, 모든 사용자 입력은 마치 악의적 인 것처럼 처리되어야합니다. 그러나 매개 변수가있는 쿼리를 사용할 때는 SQL 주입을 중지하는 가장 좋은 방법 입니다. 준비되고 매개 변수화 된 쿼리를 사용하지 않으면 SQL 삽입에 취약합니다. mysql_real_escape_string허위 보안입니다-보장되지 않습니다. 매개 변수화 된 쿼리 가 있습니다.
greyfade

나는 그것에 대해 더 자세히 읽은 후에 동의합니다. 함수 : mysql_real_escape_string은 일반적으로 대부분 안전하지만, 큰 책임이라고 생각하지 않지만 준비된 문을 사용하는 것이 훨씬 더 효율적인 방법을 알 수 있습니다.
chrisw

1
PDO를 사용할 수 있습니다.
Felix G

1

소금에 절인 단방향 해시를 사용하십시오 ( http://au2.php.net/manual/en/function.hash.php를 사용하는 SHA512가 선호 됨) . 그런 식으로 누군가가 소금을 알고 있더라도 데이터베이스를 해킹하는 경우 , 비밀번호를 추출 할 수 없습니다 (SHA512에 대한 레인보우 테이블이 없음).

HTTPS를 사용하십시오.

사용자가 등록 할 때 이메일을 통해 사용자 이름 / 암호 확인을 다시 보내지 마십시오.

쿠키를 '기억하기'로 허용하는 경우 관리 및 프로필 편집 기능에 액세스하려면 추가 로그인을 추가하십시오.

사용자가 비밀번호를 잘못 얻은 경우 비밀번호가 잘못되었다고 말하지 마십시오 (예 : '사용자 이름 또는 비밀번호가 항상 잘못되었습니다'). 그렇게하면 유효한 사용자 이름에 대한 단서가 줄어 듭니다.

화면 이름 대 로그인을 시도하여 구현하십시오. 이렇게하면 사용자 목록에 로그인 이름을 표시하는 사용자 수가 줄어 듭니다.


이메일로 일반 텍스트로 이메일을 보내지 않는 것에 대해 완전히 동의하십시오. 웹 사이트 에서이 횟수를 잃었습니다. 모든 사이트에 대해 하나의 암호가 있으면 (아쉽게도 그렇지 않습니다) 모든 웹 사이트가 손상 될 수 있습니다. 이러한 웹 사이트는 암호를 일반 텍스트로도 저장합니다. 한숨
바리 토 누크

1
  • MD5 또는 SHA1 해싱 알고리즘을 사용하지 마십시오. 항상 SHA512와 같은 새로운 것을 고수하십시오
  • 항상 강한 무작위로 생성 된 소금을 사용하십시오
  • "비밀번호 분실"의 경우에도 사용자에게 비밀번호를 이메일로 보내지 마십시오.
  • mysql_ * 함수를 사용하지 마십시오. 그들은 오랫동안 감가 상각되었습니다. PDO에 충실
  • 세션이나 쿠키에 비밀번호를 저장하지 마십시오

0

다음은 몇 가지 조언입니다. 도난을 방지하기 위해 JS로 쿠키에 액세스 할 수 없는지 확인하십시오. 쿠키 보호 : HttpOnly 기사 : Jeff Atwood

... 기발한 구성을 통해 잘못된 URL은 살균제를 지나쳐지나갑니다. 브라우저에서 볼 때 최종 렌더링 된 코드는 해당 원격 서버에서 스크립트를로드하고 실행합니다.

...이 스크립트 삽입 사용자 프로필 페이지를로드 한 사람은 자신의 브라우저 쿠키를 악의없는 원격 서버로 무심코 전송했습니다!

우리가 이미 확립했듯이, 누군가가 특정 웹 사이트에 대한 브라우저 쿠키를 가지고 있다면, 그들은 본질적으로 귀하의 정체성을 위해 왕국의 열쇠를 가지고 있습니다 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.