Posted by
The Code Post
on
- Get link
- X
- Other Apps
Metin Kriptolama
Kaynaklar
https://www.php.net/manual/en/refs.crypto.php
https://diptendud.medium.com/difference-between-aes-and-sha256-706d6b2eb2ef
https://encode-decode.com/glossary/encryption/
https://www.keyfactor.com/blog/symmetric-vs-asymmetric-encryption/
https://www.veriff.com/blog/types-of-authentication-methods
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
Metin Kriptolama Araçları
Metin kriptolama için yaygın olarak kullanılan araçlar şunlardır:
OpenSSL: Asimetrik ve Simetrik kriptolama yöntemlerini sağlar. API sistemleri için kullanılabilir. "OpenSSL is an open-source command line tool that is commonly used to generate private keys, create CSRs, install your SSL/TLS certificate, and identify certificate information."
Sodium Kütüphanesi: OpenSSL gibi Asimetrik ve Simetrik kriptolamanın yanında şifre hashleme ve dosya şifreleme/açma için de kullanılır. API sistemleri için kullanılabilir. "Sodium is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more. Its goal is to provide all of the core operations needed to build higher-level cryptographic tools."
Password Hashing (Şifre Gizleme/Hashleme) Fonksiyon ve Algoritmaları: Sunucu tarafı yazılım dillerinin sağladığı araçlardır. Temel olarak, şifrelerin sunucu veritabanında şifreli olarak kaydedilmesini ve buna uygun şekilde "Session Login" girişi yapılmasında kullanılır. Bunun yanında, adli işlemlerde bir dosyanın veri bütünlüğünün korunup korunmadığını anlamak için de kullanılır.
Metin Kriptolama Yöntemleri
1. Asimetrik Kriptolama:
OpenSSL
a. Anahtarların Oluşturulması
//PHP
$res = openssl_pkey_new(array('private_key_bits' => 2048));
/* Extract the private key from $res to $privKey */
openssl_pkey_export($res, $privKey);
/* Extract the public key from $res to $pubKey */
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];
/*Public Key Client sunucuya verilir. Client, mesajını bu anahtar ile şifreler. Her Clienta bu anahtar verilebilir. Çünkü, şifrelenen mesajı bu anahtarla açamazlar, yalnızca şifreleyebilirler.*/
echo $pubKey;
/*Private Key, sunucuda kalır. Şifreli mesaj yalnızca bu anahtarla açılabilir.*/
echo $privKey;
b. Public Key İle Mesajın Şifrelenmesi
//PHP
openssl_public_encrypt("Bu bir mesajdır.", $encrypted, $pubKey);
echo $encrypted;
c. Private Key İle Mesajın Çözümlenmesi
//PHP
openssl_private_decrypt($encrypted, $decrypted, $privKey);
echo $decrypted;
2. Simetrik Kriptolama:
OpenSSL
a. Mesajın Şifrelenmesi
//PHP
/*Initialization Vector-iv kriptonun benzersiz olmasını sağlayan rasgele bir değerdir. Kullanımda şifrelenmiş mesajla birlikte bu iv değerinin de sunucuya pas edilmesi gerekir ki sunucu mesajı çözümleyebilsin.*/
$iv="12345";
/*Şifrelenecek bilgiler*/
$params = new \stdClass();
$params->param1="Text1";
$params->param2="Text2";
/*Şifreleme*/
$algorithm = "AES-256-CBC";
$api_token = base64_encode(openssl_encrypt(json_encode($params), $algorithm, $db_api_secret, $options=OPENSSL_RAW_DATA, $iv));
/*Çıktı*/
echo $api_token;
b. Mesajın Çözümlenmesi
//PHP
/*Aynı algoritma ve iv değeriyle çözümleme*/
$iv="12345";
$algorithm = "AES-256-CBC";
$decrypted = openssl_decrypt(base64_decode($api_token), $algorithm, $db_api_secret, OPENSSL_RAW_DATA, $iv);
/*Aktarılan bilgiler*/
$post=json_decode($decrypted);
/*Çıktı*/
echo $decrypted;
Sodium Kütüphanesi
OpenSSL de aynı kelimelerin aynı şifreyi vermemesi için kullanılan iv değişkeni yerine, bu kütüphanede nonce değişkeni kullanılıyor.
a. Mesajın Şifrelenmesi
//PHP
$secret_key = sodium_crypto_secretbox_keygen();
$message = 'Sensitive information';
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted_message = sodium_crypto_secretbox($message, $nonce, $secret_key);
echo $encrypted_message;
b. Mesajın Çözümlenmesi
//PHP
$decrypted_message = sodium_crypto_secretbox_open($encrypted_message, $nonce, $secret_key);
echo $decrypted_message;
3. Tek Yönlü Kriptolama (Hashing):
a. Metnin Şifrelenmesi - Örnek Fonksiyonlar
echo hash('sha256', "Metin");
echo hash('md5', "Metin");
echo md5("Metin");
echo hash_hmac('sha256', "Metin", "Secret Password");
echo password_hash("Metin", PASSWORD_DEFAULT);
$options = [
'cost' => 11
];
echo password_hash("Metin", PASSWORD_BCRYPT, $options);
/*Bir metinden bağımsız rasgele bir token oluşturma ihtiyacı olduğunda*/
/*<PHP 7*/
$token = bin2hex(openssl_random_pseudo_bytes(64));
/*>PHP 7*/
$token = bin2hex(random_bytes(64));
b. Şifreli Metnin Karşılaştırılması
//PHP
/*Bir metnin şifrelenmesi*/
$hashed_value = hash('sha256', "Metin");
/*Aynı metnin aynı yöntemle önceden şifrelenmiş hali*/
$hashed_expected = "80422e38652c596485382fcbf77342f8b14b944d5817ec80db71891a0b8d8d92";
/*Şifreli metinle gelen metnin şifrelenmiş halinin karşılaştırılması*/
//if ($hashed_expected==$hashed_value){ //veya
if (hash_equals($hashed_expected, $hashed_value) ) {
echo "Hashes match!";
}
//PHP
/*Bir metnin şifrelenmesi*/
$hash = password_hash("Metin", PASSWORD_DEFAULT);
/*Metnin şifreli hali ile açık halinin karşılaştırılması*/
if (password_verify("Metin", $hash)) {
echo 'Password is valid!';
}
Kriptolamanın Kullanım Örnekleri
API Auth Yöntemleri
1. Basic Auth
Kullanıcı Tarafı
PHP ile
client.php
$username = 'demo';
$password = '12345';
$token = base64_encode("$username:$password");
$ch = curl_init('https://demo.proctorstone.com/docs/kriptolama/basic/api.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic ' . $token,
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Curl error: ' . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
JAVASCRIPT İle
client.html
<html>
<head>
<title> Ajax JavaScript Basic Auth Example </title>
</head>
<body>
<!-- HTML5 Input Form Elements -->
<button id="upload-button" onclick="submit()"> Submit </button>
<input id="username" value="demo">
<input id="password" value="12345">
<!-- Ajax JavaScript File Upload Logic -->
<script>
/*Dosya yüklemenin kullanıcı adı ve şifre ile yapıldığı bir örnek.*/
async function submit() {
let username=document.getElementById("username").value;
let password=document.getElementById("password").value;
let headers = new Headers();
//headers.append('Content-Type', 'text/json');
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));
/*Form bilgisi post edilmesi gerekirse aşağıdaki gibi edilebilir.*/
// let formData = new FormData();
// formData.append("file", fileupload.files[0]);
// formData.append("other_parameter", "other_value");
const response = await fetch('https://demo.proctorstone.com/docs/kriptolama/basic/api.php', {
headers: headers,
// credentials: 'user:passwd',
/*Form bilgisi post edilmesi gerekirse aşağıdakiler kullanılmalıdır.*/
// method: "POST",
// body: formData
});
const data = await response.text();
console.log(data);
alert(data);
}
</script>
</body>
</html>
Sunucu Tarafı
api.php
//PHP
function getBasicToken() {
$headers = getallheaders()['Authorization'];
// HEADER: Get the access token from the header
if (!empty($headers)) {
$auth_array = explode(" ", $headers);
$un_pw = explode(":", base64_decode($auth_array[1]));
$un = $un_pw[0];
$pw = $un_pw[1];
$params = new \stdClass();
$params->username=$un;
$params->password=$pw;
return $params;
}
return null;
}
if (isset($_SERVER['PHP_AUTH_USER'])) {
$basic_user = getBasicToken()->username;
/*Sifre kullanicidan acik geliyor.*/
$basic_password = getBasicToken()->password;
/*DB de sifreyi hashli tutuyoruz. DB'den kullanici adina karsilik gelen hashli sifreyi alıp onu gelen sifreyle karsilatiracagiz. Asagidaki kısım DB den alinan hashli sifreyi simüle ediyor. Örneğimizdeki şifre 12345. Kullanıcı tarafından da açık olarak bu şifre gelmeli.*/
$password_from_db=password_hash("12345", PASSWORD_DEFAULT);
/*Alternatif dogrulama fonksiyonları*/
/*Kullanıcdan gelen şifreyi hashleyip db dekiyle karşılaştır.*/
// $hashed_basic_password = password_hash($basic_password, PASSWORD_DEFAULT);
// if ($hashed_basic_password == $password_from_db) {
// if (hash_equals($hashed_basic_password, $password_from_db) ) {
// if ($hashed_password == crypt($user_supplied_password, $hashed_password)) {
/*Gelem sifreyi veritabanındakiyle karsilastir. Burada kullanıcıdan gelen şifre açık haliyle, veritabanından gelen hashlenmiş şifre de aynı şekilde mevcut haliyle fonksiyona konuluyor.
SIFRE VERITABANINDA HASHLENMIS HALIYLE TUTULMALIDIR.*/
if (password_verify($basic_password, $password_from_db)) {
echo 'Password is valid!';
}
else {
header('HTTP/1.0 401 Unauthorized');
header('WWW-Authenticate: Basic realm="My Website"');
echo 'Access denied.';
exit;
}
}
//PHP
2. Bearer Token - OAuth2
Kullanıcı Tarafı
PHP ile
client.php
//PHP
/* API URL */
$url = 'https://demo.proctorstone.com/docs/kriptolama/bearer/server.php';
/* Init cURL resource */
$ch = curl_init($url);
/* Array Parameter Data */
$data = ['command'=>'get_users', 'timestamp'=>$timestamp];
/* pass encoded JSON string to the POST fields */
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
/* set the content type json */
$headers = [];
$headers[] = 'Content-Type:application/xml';
$token = base64_encode("your_token");
$headers[] = "Authorization: Bearer ".$token;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
/* set return type json */
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
/* execute request */
$result = curl_exec($ch);
/* close cURL resource */
curl_close($ch);
echo $result;
//PHP
JAVASCRIPT ile
client.html
<script>
async function post_token(){
let token=btoa("your_token");
let headers = new Headers();
headers.set('Authorization', 'Bearer ' + token);
let formData = new FormData();
formData.append("command", "get_users");
const response = await fetch('https://demo.proctorstone.com/docs/kriptolama/bearer/server.php', {
headers: headers,
method: "POST",
body: formData
});
const data = await response.text();
console.log(data);
alert(data);
}
post_token();
</script>
Sunucu Tarafı
server.php
//PHP
function getBearerToken() {
$headers = getallheaders()['Authorization'];
// HEADER: Get the access token from the header
if (!empty($headers)) {
$auth_array = explode(" ", $headers);
$token = base64_decode($auth_array[1]);
// You would typically validate the token and extract relevant information here
return $token;
}
return null;
}
echo getBearerToken();
//PHP
3. Parolalı Mesaj Gönderme - JWT:
Gönderilen bilginin gizlenmesi gerekmediği, fakat gönderen kişinin kimliğinin teyit edilmesi gereken durumlarda JWT kullanılabilir. JWT, mesajın header ve payload kısmıyla birlikte, bu iki kısmın imzalanmış halinin gönderilmesinden ibarettir. İmzalı kısım, gönderilen mesajın doğru kişi tarafından ve orijinal halinden değiştirilmeden gönderildiğini ispatlar.a. JWT Oluşturma
/*Source: https://dev.to/robdwaller/how-to-create-a-json-web-token-using-php-3gml*/
// Create token header as a JSON string
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
// Create token payload as a JSON string
$payload = json_encode([
'user_id' => 1,
'role' => 'admin',
'exp' => 1593828222
]);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, 'abC123!', true);
// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
// Create JWT
$jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
echo $jwt;
b. JWT'yi Teyit Etme
/*Source: https://developer.okta.com/blog/2019/02/04/create-and-verify-jwts-in-php*/
$jwt = $argv[1];
// split the token
$tokenParts = explode('.', $jwt);
$header = base64_decode($tokenParts[0]);
$payload = base64_decode($tokenParts[1]);
$signatureProvided = $tokenParts[2];
// check the expiration time - note this will cause an error if there is no 'exp' claim in the token
$expiration = Carbon::createFromTimestamp(json_decode($payload)->exp);
$tokenExpired = (Carbon::now()->diffInSeconds($expiration, false) < 0);
// build a signature based on the header and payload using the secret
$base64UrlHeader = base64UrlEncode($header);
$base64UrlPayload = base64UrlEncode($payload);
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secret, true);
$base64UrlSignature = base64UrlEncode($signature);
// verify it matches the signature provided in the token
$signatureValid = ($base64UrlSignature === $signatureProvided);
echo "Header:\n" . $header . "\n";
echo "Payload:\n" . $payload . "\n";
if ($tokenExpired) {
echo "Token has expired.\n";
} else {
echo "Token has not expired yet.\n";
}
if ($signatureValid) {
echo "The signature is valid.\n";
} else {
echo "The signature is NOT valid\n";
}

Comments
Post a Comment