Để bảo mật thông tin giữa Server – Client, thông thường phổ biến nhất là dùng giao thức HTTPS, tuy nhiên, nếu bạn không triển khai giao thức này vì nhiều lý do khách quan / chủ quan thì vấn đề cần quan tâm trước hết chống lại việc bị “chôm” thông tin tài khoản của user trong quá trình đăng nhập hệ thống.
Lưu ý: Phương pháp trình bày sẽ giúp bạn mã hóa hóa giữ liệu trên đường truyền khi user submit tài khoản của họ (tên đăng nhập, mật khẩu), tuy nhiên, nó không thể thay thế HTTPS vì attacker có thể không nhắm đến user/pass mà sẽ chôm token của browser để giả mạo client với server.
Các bước:
- Tạo KEY bí mật giữa Server và Client để mã hóa/giải mã dữ liệu
- Tại client: mã hóa dữ liệu bằng KEY trước khi submit
- Tại server: giải mã dữ liệu nhận từ client bằng KEY, tiến hành các thủ tục thông thường
* KEY có thể xem được tại client, tuy nhiên attacker sẽ rất khó biết được KEY này, trừ khi săm soi rất kỹ mọi dữ liệu truyền trên hệ thống mạng.
Mã hóa tại client:
– Dùng $_SESSION print ra KEY trong code javascript để xử lý mã hóa dữ liệu trước khi submit lên server (KEY tạo như thế nào thì có nhiều cách, 1 cách là bạn có thể dùng MD5 kết hợp unique_id)
– Dùng javascript bắt sự kiện form submit, lấy giá trị user điền để mã hóa với KEY đã biết, thuật toán sử dụng AES 256bit
– Chèn dữ liệu đã mã hóa vào form submit, tiếp tục quá trình submit
Code ví dụ:
Lưu ý: trên thực tế bạn không muốn submit 2 trường user/pass clean mà người dùng điền, thay vào đó sẽ submit các giá trị đã mã hóa, vì vậy input username và input password bạn không đặt tên (name) cho field >> đoạn mã dưới cần sửa phần lấy giá trị theo tên thành theo id:
1 2 3 4 |
document.loginForm.username.value thành $('#id_field_username').val() ... tương tự phần password |
[codesyntax lang=”javascript”]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script> <script> $('form[name="loginForm"]').submit(function(){ //listen for submit event var serect = <?=$_SESSION['key']?>; var params = [ { name: "u", value: CryptoJS.AES.encrypt(document.loginForm.username.value, serect) }, { name: "p", value: CryptoJS.AES.encrypt(document.loginForm.password.value, serect) } ]; $.each(params, function(i,param){ $('<input />').attr('type', 'hidden') .attr('name', param.name) .attr('value', param.value) .appendTo('form[name="loginForm"]'); }); return true; }); </script> |
[/codesyntax]
Tại server:
- Giải mã dữ liệu tại client dùng KEY đã lưu trong $_SESSION
- Tiến hành xử lý các bước thông thường
[codesyntax lang=”php”]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
$user = $_POST['u']; //đã mã hóa $pass = $_POST['p']; //đã mã hóa $key = $_SESSION['key']; //Được sinh ra khi user load form login echo "Username:" sqAES::decrypt($key, $user); //giải mã echo "Password:" sqAES::decrypt($key, $pass); //giải mã class sqAES { /** * decrypt AES 256 * * @param string $password * @param data $edata * @return dencrypted data */ public static function decrypt($password, $edata) { $data = base64_decode($edata); $salt = substr($data, 8, 8); $ct = substr($data, 16); /** * From https://github.com/mdp/gibberish-aes * * Number of rounds depends on the size of the AES in use * 3 rounds for 256 * 2 rounds for the key, 1 for the IV * 2 rounds for 128 * 1 round for the key, 1 round for the IV * 3 rounds for 192 since it's not evenly divided by 128 bits */ $rounds = 3; $data00 = $password.$salt; $md5_hash = array(); $md5_hash[0] = md5($data00, true); $result = $md5_hash[0]; for ($i = 1; $i < $rounds; $i++) { $md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true); $result .= $md5_hash[$i]; } $key = substr($result, 0, 32); $iv = substr($result, 32,16); return openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv); } /** * crypt AES 256 * * @param string $password * @param data $data * @return base64 encrypted data */ public static function crypt($password, $data) { // Set a random salt $salt = openssl_random_pseudo_bytes(8); $salted = ''; $dx = ''; // Salt the key(32) and iv(16) = 48 while (strlen($salted) < 48) { $dx = md5($dx.$password.$salt, true); $salted .= $dx; } $key = substr($salted, 0, 32); $iv = substr($salted, 32,16); $encrypted_data = openssl_encrypt($data, 'aes-256-cbc', $key, true, $iv); return base64_encode('Salted__' . $salt . $encrypted_data); } } |
[/codesyntax]