PHP에서 데이터베이스 비밀번호를 보호하는 방법?


404

PHP 응용 프로그램이 데이터베이스 연결을 할 때는 물론 일반적으로 로그인과 암호를 전달해야합니다. 내 응용 프로그램에 단일 최소 권한 로그인을 사용하는 경우 PHP는 해당 로그인과 암호를 어딘가에 알아야합니다. 해당 비밀번호를 보호하는 가장 좋은 방법은 무엇입니까? PHP 코드로 작성하는 것은 좋은 생각이 아닌 것 같습니다.


1
완전히 안전하려면 SSL 연결을 설정해야합니다. 그렇지 않으면 네트워크의 모든 사용자가 여전히 입력 한 비밀번호를 스니핑 할 수 있습니다.
Charles Ma

1
연결 문자열에 사용 된 사용자 비밀번호 또는 데이터베이스 비밀번호를 의미합니까?
Ozgur Ozcitak

4
연결 문자열에 사용 된 데이터베이스 비밀번호입니다. 감사!
user18359

답변:


238

여러 사람들이 데이터베이스에 비밀번호 를 저장 하는 방법에 대한 질문으로 이것을 잘못 읽었습니다 . 그건 잘못이야 그것은 당신이 얻을 수 있습니다 암호를 저장하는 방법에 관한 것입니다 데이터베이스를.

일반적인 해결책은 암호를 소스 코드에서 구성 파일로 옮기는 것입니다. 그런 다음 관리 및 보안 구성 파일을 시스템 관리자에게 맡기십시오. 그렇게하면 개발자는 프로덕션 암호에 대해 아무것도 알 필요가 없으며 소스 제어에 암호 기록이 없습니다.


8
감사. 내가 이것을 올바르게 이해하면 PHP 파일은 구성 파일에 포함되어 암호를 사용할 수 있습니다. 예를 들어, login, pword 및 & db name을 저장하는 'app1_db_cfg.php'라는 파일을 만듭니다. 그런 다음 application.php 페이지에 'app1_db_cfg.php'가 포함되어 있으며 비즈니스에 종사하고 있습니다!
user18359

28
구성을 올바르게 보호해야한다는 데 동의합니다. 그러나 그렇게하는 방법을 아는 것은 개발자가 아닌 시스템 관리자의 업무입니다. 이 경우 강력한 암호화의 가치에 동의하지 않습니다. 설정 파일을 보호 할 수 없다면, 키를 보호 할 수 있다고 생각하는 이유는 무엇입니까?
user11318

10
웹 서버에서 데이터베이스에 액세스 할 수있는 데이터베이스 계정을 선호합니다. 그런 다음 구성을 암호화하지 않고 웹 루트 외부에 저장합니다.
gnud 2009

11
아파치 환경 변수를 사용하여 경로를 설정하여 파일 경로조차도 소스 코드에서 알 수 없습니다. 이것은 또한 서버에서 아파치 설정이 무엇인지에 따라 개발 및 생산을 위해 다른 암호를 가질 수있게 해줍니다.
geedew

15
웹에서 액세스 할 수있는 디렉토리 외부에 저장된 파일도 파일을 사용하는 스크립트에서 읽어야합니다. 누군가 해당 파일을 포함하고 파일에서 데이터를 덤프하면 비밀번호가 표시됩니다.
Rick Mac Gillis

104

다른 사람의 서버에서 호스팅하고 있고 웹 루트 외부에서 액세스 할 수없는 경우 항상 비밀번호 및 / 또는 데이터베이스 연결을 파일에 넣은 다음 .htaccess를 사용하여 파일을 잠글 수 있습니다.

<files mypasswdfile>
order allow,deny
deny from all
</files>

3
고마워요, 바로 내가 찾던 것이 었습니다.
David Gladfelter

28
확실히, 누군가 쉘 액세스 권한이 있으면 어쨌든 전체 계정이 도용 된 것입니다.
kellen

4
자격 증명을 리포지토리에 실수로 커밋 할 수 있으므로이 방법은 좋지 않습니다.
Porlune 2016 년

2
@Ankit : 비 친절한 파일을 서버에 업로드하여 실행할 수 있으면 서버가 올바르게 구성되지 않은 것입니다.
kellen

6
@Porlune : 개발자는 버전 관리 시스템이 암호 파일을 무시하도록해야합니다 (예 : .gitignore 사용). 그러나 예, 중요한 데이터가 포함 된 파일은주의해야합니다.
kellen

45

가장 안전한 방법은 PHP 코드에 정보를 지정하지 않는 것입니다.

Apache를 사용하는 경우 httpd.conf 또는 가상 호스트 파일 파일에서 연결 세부 정보를 설정하는 것을 의미합니다. 그렇게하면 매개 변수없이 mysql_connect ()를 호출 할 수 있습니다. 즉, PHP는 절대로 정보를 출력하지 않습니다.

이러한 파일에서 이러한 값을 지정하는 방법은 다음과 같습니다.

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

그런 다음 다음과 같이 mysql 연결을 엽니 다.

<?php
$db = mysqli_connect();

또는 이렇게 :

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));

1
ini_get ( 'default values')의 올바른 값을 확인하십시오. php.net/manual/en/class.mysqli.php
Val

4
예, 그러나 모든 사용자 (또는 잘못 작성된 PHP 스크립트를 악용하는 해커)는을 통해 비밀번호를 읽을 수 있습니다 ini_get().
Marki555

1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()어떻게 처리합니까?
tonix

2
Marki555는 PHP 코드를 실행할 수있는 공격자가 PHP 함수를 호출 할 수도 있다고 말하고 있습니다. 또한 더 이상이 답변에서 제공하는 조언을 따르지 않고 환경 변수를 사용한다고 덧붙이고 싶습니다. 개념은 비슷하지만 자격 증명을 코드에 저장하지 말고 어떻게 든 주입하십시오. 당신이 사용하는 경우 그것은 정말 중요하지 않습니다 ini_get()또는 getenv().
Lars Nyström

2
@DeepBlue ini_get ()을 주입 할 수 있으면 file_get_contents (anypath)도 주입 할 수 있습니다. PHP가 암호를 얻는 방법이 있다면 악성 코드도 마찬가지입니다.
varesa

40

웹 루트 외부의 파일에 저장하십시오.


29
또한 다른 곳에서 언급했듯이 소스 제어 외부.
Frank Farmer

6
우리는 그것을 포함시킬 수 있을까요? 예를 들어 PHP에서 우리는 할 수 include('../otherDirectory/configfile.conf')있습니까?
mtk

1
여러분은 wwwroot 외부에 자격 증명을 저장하도록 제안하고 있습니다. 좋아, 나는 보안 배경을 이해한다. 그러나 어떻게 버전 제어에 저장해야합니까 (샘플 설정)? 일반적으로 wwwroot는 git repo의 루트이므로 외부에 무언가가 있으면 VC 외부에 있습니다. 새로운 개발자가 개발을 위해 로컬 인스턴스를 설정하려고한다고 상상해보십시오. "이 파일을 가져 와서 외부에 복사하여 채우십시오"와 같은 마법을 어떻게 알아야합니까?
대부

@TheGodfather 아이디어는 새로운 개발자가 자신의 개발 환경에 대한 자신의 자격 증명을 가져야한다는 것입니다. 코드에 지침 또는 주석이 포함 된 readme를 구성하는 방법 (실제 데이터는 아님)을 나타내는 것이 좋습니다.
PhoneixS

@TheGodfather, readme 파일?
Pacerier

35

매우 안전한 시스템의 경우 구성 파일 (시스템 관리자가 자체적으로 보안)로 데이터베이스 비밀번호를 암호화합니다. 응용 프로그램 / 서버 시작시 응용 프로그램은 시스템 관리자에게 암호 해독 키를 요구합니다. 그런 다음 구성 파일에서 데이터베이스 비밀번호를 읽고 암호 해독 한 후 나중에 사용할 수 있도록 메모리에 저장합니다. 해독 된 메모리에 저장되어 있기 때문에 여전히 100 % 안전하지는 않지만 어느 시점에서 그것을 충분히 안전하다고해야합니다!


85
관리자가 사망하면 어떻게됩니까?
Radu Murzea

36
@RaduMurzea 그건 말도 안됩니다. Sys Admins의 사망에 대해 언제 들었습니까? 그들은 맥도날드와 같습니다. 그들은 어디에서나 나타나거나 사라집니다!
ILikeTacos

13
@Radu Murzea 2 명 이상의 관리자 만 있으면 레이드 배열과 같은 패리티를 갖습니다. 한 번에 둘 이상의 드라이브 장애가 발생할 가능성이 훨씬 낮습니다.
element11

5
서버가 다시 시작되면 어떻습니까? 비밀번호 등을 입력하기 위해 관리자를 깨우는 데 걸리는 시간은 어떻습니까? lol
John Hunt

1
'메모리에 저장 됨'이 무슨 뜻인지 잘 모르겠습니다. PHP 웹 앱은 일반적으로 개별 요청에 응답하여 페이지를 보는 데 걸리는 시간보다 오래 메모리에 아무것도 저장하지 않습니다.
bdsl

15

이 솔루션은 일반적으로 공개 소스 애플리케이션과 폐쇄 소스 애플리케이션 모두에 유용합니다.

  1. 응용 프로그램의 OS 사용자를 작성하십시오. http://en.wikipedia.org/wiki/Principle_of_least_privilege 참조
  2. 비밀번호를 사용하여 해당 사용자에 대한 (비 세션) OS 환경 변수를 작성하십시오.
  3. 해당 사용자로 애플리케이션을 실행하십시오.

장점 :

  1. 실수로 비밀번호를 소스 제어에 체크인하지 않습니다.
  2. 실수로 파일 권한을 망치지 않습니다. 글쎄, 당신은 할 수 있지만, 이것에는 영향을 미치지 않습니다.
  3. 루트 또는 해당 사용자 만 읽을 수 있습니다. 어쨌든 루트는 모든 파일과 암호화 키를 읽을 수 있습니다.
  4. 암호화를 사용하는 경우 키를 어떻게 안전하게 저장합니까?
  5. x- 플랫폼 작동
  6. envvar를 신뢰할 수없는 자식 프로세스로 전달하지 마십시오.

이 방법은 매우 성공적인 Heroku가 제안합니다.


11

신임 정보가 저장된 동일한 파일에서 데이터베이스 연결을 작성할 수있는 경우. connect 문의 신임 정보를 인라인하십시오.

mysql_connect("localhost", "me", "mypass");

그렇지 않으면 메모리에없는 자격 증명을 메모리에서 읽을 수 없으므로 connect 문 다음에 자격 증명을 설정 해제하는 것이 가장 좋습니다 .)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  

9
누군가 메모리에 액세스 할 수 있다면 어쨌든 망가진 것입니다. 이것은 무의미한 가짜 보안입니다. 웹 루트 외부 (또는 웹 루트 이상으로 액세스 할 수없는 경우 .htaccess로 최소한 보호됨)만이 유일한 안전한 옵션입니다.
uliwitness

2
@uliwitness-누군가가 아세틸렌 토치로 네트워크 운영 센터의 자물쇠를 뚫을 수 있기 때문에 문이 가짜 보안임을 의미합니다. 민감한 정보를 가능한 한 좁은 범위에 묶는 것은 항상 의미가 있습니다.
Luke A. Leber

1
echo $ db_user 또는 $ db_pass 인쇄는 어떻습니까? 같은 팀의 개발자조차도 프로덕션 자격 증명을 파악할 수 없어야합니다. 코드에는 로그인 정보에 대해 인쇄 가능한 것이 포함되어 있지 않아야합니다.
Mohammed Joraid

8

데이터베이스에 액세스하기 위해 암호가 필요하다고 말했듯이 선택은 제한적입니다. 일반적인 접근 방법 중 하나는 사용자 이름과 비밀번호를 기본 스크립트가 아닌 별도의 구성 파일에 저장하는 것입니다. 그런 다음 기본 웹 트리 외부에 저장하십시오. PHP 파일이 실행되지 않고 단순히 텍스트로 표시되는 웹 구성 문제가있는 경우 암호를 노출하지 않았습니다.

그 외에는 사용중인 계정에 대한 최소한의 액세스 권한만으로 올바른 회선에 있습니다. 그것에 추가

  • 다른 용도로 사용자 이름 / 비밀번호 조합을 사용하지 마십시오
  • 해당 사용자에 대한 웹 호스트로부터의 연결 만 허용하도록 데이터베이스 서버를 구성하십시오 (DB가 동일한 머신에있는 경우 localhost가 더 좋습니다). 이렇게하면 신임 정보가 노출 되더라도 다른 사용자가 기계.
  • 암호를 난독 처리하십시오 (ROT13조차도). 일부는 파일에 액세스 할 경우 많은 방어를하지는 않지만 최소한 암호를 보지 못하게합니다.

베드로


8

PostgreSQL을 사용하는 경우 ~/.pgpass암호를 자동으로 찾습니다 . 자세한 내용 은 설명서 를 참조하십시오.


8

이전에는 DB 사용자 / 패스를 구성 파일에 저장했지만 이후 심층 방어 정책을 채택하여 편집증 모드에 도달 했습니다 .

응용 프로그램이 손상된 경우 사용자는 구성 파일에 대한 읽기 권한을 가지므로 크래커가이 정보를 읽을 가능성이 있습니다. 구성 파일은 버전 제어에 걸리거나 서버에서 복사 될 수도 있습니다.

Apache VirtualHost에 설정된 환경 변수에 사용자 / 패스를 저장하도록 전환했습니다. 이 구성은 루트 만 읽을 수 있습니다. Apache 사용자가 루트로 실행되고 있지 않기를 바랍니다.

이것의 단점은 이제 암호가 전역 PHP 변수에 있다는 것입니다.

이 위험을 완화하기 위해 다음과 같은 예방책이 있습니다.

  • 비밀번호가 암호화되었습니다. 암호 해독을위한 논리를 포함하도록 PDO 클래스를 확장합니다. 누군가 우리가 연결을 설정하는 코드를 읽으면 암호 자체가 아닌 암호화 된 암호로 연결이 설정되어 있는지 확실하지 않습니다.
  • 암호화 된 비밀번호는 글로벌 변수에서 개인 변수로 이동됩니다 . 애플리케이션은이를 사용하여 글로벌 공간에서 값을 사용할 수있는 창을 즉시 줄입니다.
  • phpinfo()비활성화되어 있습니다. PHPInfo는 환경 변수를 포함하여 모든 것에 대한 개요를 얻는 쉬운 대상입니다.

6

데이터베이스 비밀번호를 파일에 넣고 파일을 제공하는 사용자에게 읽기 전용으로 설정하십시오.

PHP 서버 프로세스가 데이터베이스에 액세스하도록 허용하는 수단이 없다면, 이것은 당신이 할 수있는 모든 것입니다.


5

브라우저에서 오는 암호와 달리 데이터베이스 암호에 대해 이야기하는 경우 표준 연습은 데이터베이스 암호를 서버의 PHP 구성 파일에 넣는 것 같습니다.

비밀번호가 포함 된 PHP 파일에 적절한 권한이 있는지 확인하면됩니다. 즉, 웹 서버와 사용자 계정으로 만 읽을 수 있어야합니다.


1
불행히도 PHP 설정 파일은 phpinfo ()로 읽을 수 있으며 누군가가 테스트 스크립트를 남긴 경우 운이 좋은 공격자가 암호를 읽을 수 있습니다. 대신 웹 서버 루트 외부의 파일에 연결 암호를 남겨 두는 것이 가장 좋습니다. 그런 다음 액세스 할 수있는 유일한 방법은 셸을 사용하거나 임의 코드를 실행하는 것이지만이 시나리오에서는 모든 보안이 손실됩니다.
MarioVilas

5

구성 파일에 어딘가에 넣는 것이 일반적으로 수행되는 방식입니다. 다음을 확인하십시오.

  1. 네트워크 외부의 모든 서버에서 데이터베이스 액세스를 허용하지 않습니다.
  2. 실수로 사용자에게 비밀번호를 표시하지 않도록주의하십시오 (오류 메시지 또는 실수로 HTML 등으로 제공되는 PHP 파일을 통해).

5

우리는 이것을 다음과 같이 해결했습니다.

  1. 다른 비밀번호 서버에서 열린 연결로 서버에서 memcache를 사용하십시오.
  2. 암호 (또는 암호화 된 모든 password.php 파일)와 암호 해독 키를 memcache에 저장하십시오.
  3. 웹 사이트는 암호 파일 암호를 보유한 memcache 키를 호출하고 모든 암호를 메모리에서 해독합니다.
  4. 비밀번호 서버는 5 분마다 새 암호화 된 비밀번호 파일을 보냅니다.
  5. 프로젝트에서 암호화 된 password.php를 사용하는 경우이 파일이 외부에 닿았는지 또는 열렸는지 확인하는 감사가 이루어집니다. 이 경우 메모리를 자동으로 정리하고 서버를 닫아 액세스 할 수 있습니다.

4

추가 트릭은 다음과 같은 PHP 별도의 구성 파일을 사용하는 것입니다.

<?php exit() ?>

[...]

Plain text data including password

이것은 액세스 규칙을 올바르게 설정하는 것을 방해하지 않습니다. 그러나 웹 사이트가 해킹 된 경우 "필수"또는 "포함"은 첫 번째 줄에서 스크립트를 종료하기 때문에 데이터를 얻기가 훨씬 더 어렵습니다.

그럼에도 불구하고 웹을 통해 액세스 할 수있는 디렉토리에 구성 파일을 두지 마십시오. 제어 코드, CSS, 그림 및 JS가 포함 된 "Web"폴더가 있어야합니다. 그게 다야. 다른 것은 오프라인 폴더에 들어갑니다.


그러나 PHP 스크립트는 파일에 저장된 자격 증명을 어떻게 읽습니까?
Christopher Mahan

3
일반 텍스트 파일처럼 fopen ()을 사용합니다.
e-satis

2
@ 전자 satis 확인이 수행하는 해커를 방지 할 수 있습니다 require/ include하지만 어떻게 할 방지하기 위해 fopen?
dmnc

"이것이 액세스 규칙을 올바르게 설정하는 것을 방해하지는 않습니다"
e-satis

@ e-satis, 이것은 꽤 영리합니다. 아무도 왜 그런 생각을하지 않았는지 궁금합니다. 그러나 여전히 편집기 복사 문제에 취약합니다. feross.org/cmsploit
Pacerier

4

가장 좋은 방법은 암호를 전혀 저장하지 않는 것입니다!
예를 들어 Windows 시스템에 있고 SQL Server에 연결하는 경우 통합 인증을 사용하여 현재 프로세스의 ID를 사용하여 암호없이 데이터베이스에 연결할 수 있습니다.

당신은 암호를 먼저 연결해야하는 경우 암호화 를 (예 : AES-256을 사용하고 암호화 키를 보호하거나 인증서를 보호하는 OS를 비대칭 암호화를 사용하고있다) 강력한 암호화를 사용하여 다음에 저장을 강력한 ACL 이있는 구성 파일 (웹 디렉토리 외부) .


3
암호를 다시 암호화 할 필요가 없습니다 . 암호화되지 않은 암호를 얻을 수있는 사람도 암호를 해독하는 데 필요한 암호를 얻을 수 있습니다. 그러나 ACL 및 .htaccess를 사용하는 것이 좋습니다.
uliwitness

2
@uliwitness 나는 당신이 오해했을지도 모른다고 생각한다- " 다시 암호화하다"는 무엇을 의미 하는가? 하나의 암호화 일뿐입니다. 또한 암호 구문 (인간 용)을 사용하여 암호화하지 않고, 파일 시스템에 액세스하는 것만으로 키에 대한 액세스 권한을 부여하지 않는 방식으로 OS에 의해 보호되는 것과 같은 강력한 키 관리를 원하지 않습니다.
AviD

3
암호화는 마술이 아닙니다. ACL로 AES 키를 보호하는 대신 암호를 저장할 수 있습니다. AES 키 또는 암호 해독 된 암호에 액세스하는 것에는 차이가 없습니다. 이러한 맥락에서 암호화는 단지 뱀 오일입니다.
MarioVilas

@MarioVilas whaat? OS가 보호하는 암호화 키를 사용하여 암호가 암호화 된 경우 어떻게 다른 점이 있습니까? 암호화는 마술이 아닙니다. 모든 비밀을 더 작은 암호화 키로 압축합니다. 거의 유일하게,이 맥락에서 그것은 모든 비밀을 OS로 옮기고 있습니다.
AviD

6
@AviD 어떻게 OS가 키를 보호 할 수 있지만 데이터 자체는 보호하지 못합니까? 답변 : 둘 다 보호 할 수 있으므로 암호화가 실제로 도움이되지 않습니다. 데이터 만 저장되고 암호화 키가 예를 들어 사용자 가 입력해야하는 암호에서 파생 된 경우에는 달라집니다 .
MarioVilas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.