Menu

Tuesday, February 25, 2020

[Laravel - Model] การเข้ารหัสและถอดรหัสค่าของฟิลด์ใน Laravel Model โดยใช้ SSH Keys
[Laravel - Model] Field Values Encryption and Decryption in Laravel Model by Using SSH Key

สืบเนื่องจากโพสต์ [Laravel - Model] การเข้ารหัสและถอดรหัสค่าของฟิลด์ใน Laravel Model ที่เราเข้ารหัสข้อมูลก่อนเก็บลงฐานข้อมูล โดยใช้การเข้ารหัสและถอดรหัสของ Laravel ซึ่งใช้ APP_KEY ใน .env เป็น key ทำให้คนที่เข้าถึง application สามารถถอดรหัสข้อมูลได้

เพื่อเพิ่มความปลอดภัยขึ้นไปอีกขั้น เราจะเปลี่ยนจากการใช้ APP_KEY ใน .env เป็น SSH Keys ซึ่งแยกเป็น Public key และ Private key แทน โดยเราจะได้เพียง Public key มาใช้ในการเข้ารหัส แต่คนมีสิทธิ์ดูข้อมูลเท่านั้นที่จะมี Private key เพื่อใช้ถอดรหัสข้อมูล

โค้ดของ Trait เป็นดังนี้
<?php

namespace App\Traits;

use phpseclib\Crypt\RSA;
use App\Exceptions\NoPublicKeyException;
use App\Exceptions\NoPrivateKeyException;

trait SSHEncryptable
{
    /**
     * If the attribute is in the encryptable array
     * then decrypt it.
     *
     * @param $key
     *
     * @return $value
     */
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);
        if (isset($this->encryptable) && in_array($key, $this->encryptable) && $value !== '') {
            $value = $this->decrypt($value);
        }
        return $value;
    }

    /**
     * If the attribute is in the encryptable array
     * then encrypt it.
     *
     * @param $key
     * @param $value
     */
    public function setAttribute($key, $value)
    {
        if (isset($this->encryptable) && in_array($key, $this->encryptable)) {
            $value = $this->encrypt($value);
        }
        return parent::setAttribute($key, $value);
    }

    /**
     * When need to make sure that we iterate through
     * all the keys.
     *
     * @return array
     */
    public function attributesToArray()
    {
        $attributes = parent::attributesToArray();
        if (isset($this->encryptable)) {
            foreach ($this->encryptable as $key) {
                if (isset($attributes[$key])) {
                    $attributes[$key] = $this->decrypt($attributes[$key]);
                }
            }
            return $attributes;
        }
    }

    private function encrypt($value)
    {
        if (!empty($this->publicKey)) {
$rsa = new RSA(); $rsa->loadKey($this->publicKey); return $rsa->encrypt($value); } throw new NoPublicKeyException(); } private function decrypt($value) { if (!empty($this->privateKey)) { $rsa = new RSA(); $rsa->loadKey($this->privateKey); return $rsa->decrypt($value); } throw new NoPrivateKeyException(); } }
โดยที่
  • getAttribute($key) เป็น function ที่ถูกเรียกโดยอัตโนมัติ เมื่อมีการดึงค่า Attribute
  • setAttribute($key, $value) เป็น function ที่ถูกเรียกโดยอัตโนมัติ เมื่อมีการตั้งค่า Attribute
  • attributesToArray() เป็น function ที่ถูกเรียกโดยอัตโนมัติ เมื่อมีแปลง Attributes ทั้งหมดของ Model ไปเป็น Array
วิธีการใช้งาน Trait ข้างต้นเป็นดังนี้
  1. ประกาศ use App\Traits\SSHEncryptable;
  2. ใส่ use SSHEncryptable; ใน Model Class
  3. ตั้งค่า fields ที่ต้องการเข้ารหัสใน $encryptable
  4. ตั้งค่า $publicKey และ $privateKey
ตัวอย่างการใช้งาน Trait ข้างต้นเป็นดังนี้
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\SSHEncryptable;
class UserSalary extends Model
{
    use SSHEncryptable;

    protected $publicKey;
    protected $privateKey;

    public function __construct(array $attributes = array())
    {
        parent::__construct($attributes);

        $this->publicKey = env('PUBLIC_KEY');
        $this->privateKey = Cache::get('private_key');
    }
    protected $fillable = [
        'user_id',
        'payroll',
        'start_at',
        'end_at',
    ];
    protected $encryptable = [
        'payroll',
    ];
}
สำหรับคนที่ต้อง Package ที่สามารถติดตั้งได้เลย เข้าไปที่ Laravel Model SSH Encryptable

No comments:

Post a Comment