PHP を使用してパスワードを暗号化および復号化する最良の方法は何ですか?[重複]
-
18-09-2019 - |
質問
重複の可能性:
PHP 双方向暗号化:取得できるパスワードを保存する必要がある
ユーザーの外国アカウント情報 (別名 Rapidshare ユーザー名とパスワードなど) を Web サイトに保存する予定です。情報を安全に保ちたいのですが、相手の情報をハッシュすると、後で使用するために取得できないことはわかっています。
Base64 は復号化可能なので、そのまま使用する意味はありません。私のアイデアは、ユーザーをスクランブルして、base64 化される前後に渡すことです。復号化した後でも、復号化しようとすると、おかしな見た目のテキストが得られます。文字列を一意にスクランブルし、後で値が再入力されたときにスクランブルを解除する値を受け入れるphp関数はありますか?
助言がありますか?
解決
パスワードは暗号化せず、代わりに bcrypt などのアルゴリズムを使用してハッシュする必要があります。 この回答では、PHP でパスワード ハッシュを適切に実装する方法について説明します. それでも、暗号化/復号化する方法は次のとおりです。
$key = 'password to (en/de)crypt';
$string = ' string to be encrypted '; // note the spaces
暗号化するには:
$iv = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$encrypted = base64_encode(
$iv .
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $key, true),
$string,
MCRYPT_MODE_CBC,
$iv
)
);
復号化するには:
$data = base64_decode($encrypted);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$decrypted = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $key, true),
substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
MCRYPT_MODE_CBC,
$iv
),
"\0"
);
警告:上記の例では情報を暗号化しますが、改ざんを防ぐために暗号文を認証しません。 あなたがすべき ない セキュリティのために未認証の暗号化に依存する, 特に、提供されたコードはパディングオラクル攻撃に対して脆弱であるためです。
以下も参照してください。
- https://stackoverflow.com/a/30189841/2224584
- https://stackoverflow.com/a/30166085/2224584
- https://stackoverflow.com/a/30159120/2224584
また、暗号化キーに単に「パスワード」を使用しないでください。 暗号化キーはランダムな文字列です。
echo 'Encrypted:' . "\n";
var_dump($encrypted); // "m1DSXVlAKJnLm7k3WrVd51omGL/05JJrPluBonO9W+9ohkNuw8rWdJW6NeLNc688="
echo "\n";
echo 'Decrypted:' . "\n";
var_dump($decrypted); // " string to be encrypted "
他のヒント
セキュリティ警告:このクラスは安全ではありません。使用しています ラインダール256-ECB, 、意味的に安全ではありません。「機能する」からといって「安全である」とは限りません。また、適切なパディングを使用しないため、後で末尾のスペースが削除されます。
最近このクラスを見つけました。夢のように機能します。
class Encryption {
var $skey = "yourSecretKey"; // you can change it
public function safe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
public function safe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
public function encode($value){
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
return trim($this->safe_b64encode($crypttext));
}
public function decode($value){
if(!$value){return false;}
$crypttext = $this->safe_b64decode($value);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
}
そしてそれを呼び出すと:
$str = "My secret String";
$converter = new Encryption;
$encoded = $converter->encode($str );
$decoded = $converter->decode($encoded);
echo "$encoded<p>$decoded";
セキュリティ警告: このコードは安全ではありません。
実例
define('SALT', 'whateveryouwant');
function encrypt($text)
{
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SALT, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
function decrypt($text)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SALT, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
$encryptedmessage = encrypt("your message");
echo decrypt($encryptedmessage);
暗号化を扱う際に十分に注意しなければならないことが 1 つあります。
賢くなろうとして、自分で何かを発明しようとすると、たいてい何か不安が残ります。
おそらく、次のいずれかを使用するのが最善でしょう。 暗号化拡張機能 PHP に付属しているものです。
これでは、最低限の保護しか得られません。攻撃者がアプリケーション内で任意のコードを実行できる場合、アプリケーションとまったく同じ方法でパスワードを取得できます。秘密キーをファイルに保存し、それを使用してデータベースへの送信時に暗号化し、出力時に復号化することで、一部の SQL インジェクション攻撃やデータベースのバックアップの置き忘れからある程度の保護を得ることができます。ただし、SQL インジェクションの問題を完全に回避するには、bindparams を使用する必要があります。
暗号化することにした場合は、これに高レベルの暗号化ライブラリを使用する必要があります。 意思 誤解してください。キーのセットアップ、メッセージ パディング、整合性チェックを正しく行う必要があります。そうしないと、暗号化の努力はほとんど役に立ちません。 GPGME 一例としては良い選択です。Mcrypt はレベルが低すぎるため、おそらく間違ってしまうでしょう。
セキュリティ警告:このコードは 不安な. 。選択暗号文攻撃に対して脆弱であることに加えて、
unserialize()
PHP オブジェクト インジェクションに対して脆弱になります。
文字列/配列を処理するには、次の 2 つの関数を使用します。
function encryptStringArray ($stringArray, $key = "Your secret salt thingie") {
$s = strtr(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), serialize($stringArray), MCRYPT_MODE_CBC, md5(md5($key)))), '+/=', '-_,');
return $s;
}
function decryptStringArray ($stringArray, $key = "Your secret salt thingie") {
$s = unserialize(rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode(strtr($stringArray, '-_,', '+/=')), MCRYPT_MODE_CBC, md5(md5($key))), "\0"));
return $s;
}
文字列/配列は暗号化前にシリアル化されるため、URL 経由で文字列または配列を保存/送信できるため、柔軟性が高くなります。
mycrypt() を確認してください。 http://us.php.net/manual/en/book.mcrypt.php
postgres を使用している場合は、データベース レベルの暗号化に pgcrypto があります。(検索や並べ替えが容易になります)
コードにアクセスできる場合でも、データベース内のデータを暗号化/復号化する最善の方法は、プライベート パスワード (user-pass
) 各ユーザーのプライベート コードとすべてのユーザーのプライベート コード (system-pass
).
シナリオ
user-pass
これは md5 とともにデータベースに保存され、各ユーザーがシステムにログインすることを検証するために使用されます。このユーザーパスは 違う ユーザーごとに。- データベース内の各ユーザー エントリには、md5 に
system-pass
データの暗号化/復号化に使用します。このシステムパスは、 同じ ユーザーごとに。 - ユーザーがシステムから削除される場合は常に、セキュリティの問題を回避するために、古いシステム パスで暗号化されているすべてのデータを新しいシステム パスで再度暗号化する必要があります。