Hướng dẫn dùng cryptography nonce trong PHP

Nonces là một lon giun.

Không, thực sự, một trong những động lực cho một số mục CAESAR là thiết kế một lược đồ mã hóa đã được xác thực, tốt nhất là dựa trên mật mã dòng, có khả năng chống lại việc sử dụng lại. [Ví dụ: sử dụng lại nonce với AES-CTR, phá hủy tính bảo mật của thông điệp của bạn ở mức độ mà một sinh viên lập trình năm nhất có thể giải mã nó.]

Có ba trường phái tư tưởng chính về phices:

  1. Trong mật mã khóa đối xứng: Sử dụng bộ đếm tăng dần, đồng thời cẩn thận để không bao giờ sử dụng lại nó. [Điều này cũng có nghĩa là sử dụng một bộ đếm riêng biệt cho người gửi và người nhận.] Điều này yêu cầu lập trình trạng thái [tức là lưu trữ nonce ở đâu đó để mỗi yêu cầu không bắt đầu tại 1].
  2. Các dấu ngoặc nhọn ngẫu nhiên trạng thái. Tạo một nonce ngẫu nhiên và sau đó ghi nhớ nó để xác thực sau. Đây là chiến lược được sử dụng để đánh bại các cuộc tấn công CSRF, nghe có vẻ gần với những gì được yêu cầu ở đây.
  3. Các nonces ngẫu nhiên không trạng thái lớn. Với một trình tạo số ngẫu nhiên an toàn, bạn gần như có thể đảm bảo không bao giờ lặp lại hai lần trong đời. Đây là chiến lược được sử dụng bởi NaCl để mã hóa.

Vì vậy, với suy nghĩ đó, các câu hỏi chính cần đặt ra là:

  1. Trường phái tư tưởng nào ở trên phù hợp nhất với vấn đề bạn đang cố gắng giải quyết?
  2. Làm thế nào bạn đang tạo ra nonce?
  3. Làm thế nào bạn xác nhận nonce?

Tạo một Nonce

Câu trả lời cho câu hỏi 2 cho bất kỳ trường hợp ngẫu nhiên nào là sử dụng CSPRNG. Đối với các dự án PHP, điều này có nghĩa là một trong những:

  • random_bytes[] cho các dự án PHP 7+
  • paragonie / random_compat , một polyfill PHP 5 chorandom_bytes[]
  • ircmaxell / RandomLib , là một con dao quân đội Thụy Sĩ về các tiện ích ngẫu nhiên mà hầu hết các dự án xử lý tính ngẫu nhiên [ví dụ: đặt lại mật khẩu linh sam] nên xem xét sử dụng thay vì sử dụng

Hai điều này tương đương nhau về mặt đạo đức:

$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator[];
$_SESSION['nonce'] [] = $generator->generate[32];

$_SESSION['nonce'] []= random_bytes[32];

Xác thực một Nonce

Trạng thái

Các dấu ngoặc nhọn trạng thái rất dễ dàng và được khuyến nghị:

$found = array_search[$nonce, $_SESSION['nonces']];
if [!$found] {
    throw new Exception["Nonce not found! Handle this or the app crashes"];
}
// Yay, now delete it.
unset[$_SESSION['nonce'][$found]];

Hãy thay thế array_search[]bằng cơ sở dữ liệu hoặc tra cứu bộ nhớ đệm, v.v.

Không trạng thái [ở đây là rồng]

Đây là một vấn đề khó giải quyết: Bạn cần một số cách để ngăn chặn các cuộc tấn công phát lại, nhưng máy chủ của bạn hoàn toàn mất trí nhớ sau mỗi yêu cầu HTTP.

Giải pháp lành mạnh duy nhất sẽ là xác thực ngày / giờ hết hạn để giảm thiểu tính hữu ích của các cuộc tấn công phát lại. Ví dụ:

// Generating a message bearing a nonce
$nonce = random_bytes[32];
$expires = new DateTime['now']
    ->add[new DateInterval['PT01H']];
$message = json_encode[[
    'nonce' => base64_encode[$nonce],
    'expires' => $expires->format['Y-m-d\TH:i:s']
]];
$publishThis = base64_encode[
    hash_hmac['sha256', $message, $authenticationKey, true] . $message
];

// Validating a message and retrieving the nonce
$decoded = base64_decode[$input];
if [$decoded === false] {
    throw new Exception["Encoding error"];
}
$mac = mb_substr[$decoded, 0, 32, '8bit']; // stored
$message = mb_substr[$decoded, 32, null, '8bit'];
$calc = hash_hmac['sha256', $message, $authenticationKey, true]; // calcuated
if [!hash_equals[$calc, $mac]] {
    throw new Exception["Invalid MAC"];
}
$message = json_decode[$message];
$currTime = new DateTime['NOW'];
$expireTime = new DateTime[$message->expires];
if [$currTime > $expireTime] {
    throw new Exception["Expired token"];
}
$nonce = $message->nonce; // Valid [for one hour]

Một người quan sát cẩn thận sẽ lưu ý rằng về cơ bản đây là một biến thể không tuân thủ tiêu chuẩn của Mã thông báo web JSON .

30 hữu ích 2 bình luận chia sẻ

Chủ Đề