jacknoordhuis/laravel-database-hashing

用于在 Laravel 5.5+ 中自动哈希 Eloquent 属性的软件包。

2.0.0 2019-03-03 08:33 UTC

This package is auto-updated.

Last update: 2024-09-29 05:33:01 UTC


README

用于自动哈希 Eloquent 属性的软件包!

Build Status

此库的目的是创建一个“设置后即可忽略”的软件包,无需太多努力即可安装,以对存储在数据库表中的 Eloquent 模型属性进行哈希处理。

启用后,此软件包将自动哈希您指定为在更新时哈希的属性所分配的数据。这允许您隐藏属性的字面值,同时仍能维护搜索数据库以查找该值的能力(相同的输入数据将始终产生相同的哈希)。

此软件包哈希的所有数据都将有一个应用程序特定的盐,该盐在配置文件或环境文件中指定,因此使用不同的盐在另一个应用程序中哈希相同的数据将产生不同的输出。这为尝试通过暴力破解哈希来重建您的攻击者增加了复杂性和保护层。如果这还不够,此软件包还支持在应用程序盐之上提供二级盐,但此功能不能直接配置为自动应用于属性。

安装

步骤 1: Composer

通过命令行

$ composer require jacknoordhuis/laravel-database-hashing ^2.0

或将软件包添加到您的 composer.json

{
    "require": {
        "jacknoordhuis/laravel-database-hashing": "^2.0"
    }
}

步骤 2: 启用软件包

此软件包实现了 Laravel 5.5 的软件包自动发现功能。安装后,软件包提供者和外观将自动注册。

如果您想明确声明提供者或别名,可以首先将服务提供者添加到您的 config/app.php 文件

'providers' => [
    //
    \jacknoordhuis\database\hashing\HashingServiceProvider::class,
];

然后,将别名添加到您的 config/app.php 文件

'aliases' => [
    //
    'DatabaseHashing' => \jacknoordhuis\database\hashing\HashingFacade::class,
];

步骤 3: 配置软件包

发布软件包配置文件

$ php artisan vendor:publish --provider="jacknoordhuis\database\hashing\HashingServiceProvider"

现在,您可以通过编辑 config/database-hashing.php 文件来启用自动哈希 Eloquent 模型

return [
    "enabled" => env("DB_HASHING_ENABLED", true),
];

或通过 Laravel 的 .env 文件或托管环境设置 DB_HASHING_ENABLED 环境变量为 true。

DB_HASHING_ENABLED=true

使用方法

在您希望应用自动属性哈希的任何 Eloquent 模型中使用 HasHashedAttributes 特性,并定义一个包含要自动哈希的属性的 protected $hashing 数组。

例如

use jacknoordhuis\database\hashing\traits\HasHashedAttributes;

class User extends Model
{
    use HasHashedAttributes;
   
    /**
     * The attributes that should be hashed when set.
     *
     * @var array
     */
    protected $hashing = [
        'username_lookup',
    ];
}

查找哈希值

您可以通过简单地对您要搜索的值进行哈希处理来在数据库表中查找哈希值,因为结果哈希始终相同。

$user->username_lookup = $request->get('username'); //the username_lookup attribute will be automatically hashed


//when our user tries to login we just search the database for the hashed value of their username
$user = User::where('username_lookup', DatabaseHashing::create($request->get("username"))->first();

您还可以在直接哈希数据时可选地提供盐修饰符,这将在应用程序级盐之上增加另一层复杂性和安全性。

//with a salt modifier so we can only ever re-create the hash when the user provides their email or we could store an
//encrypted copy ourselves with another package
$user->username_lookup = $request->get('username'); //set the attribute, then hash manually because we use a modifier
$user->hashAttribute('username_lookup', $request->get('username')); //this time add the plain text email as a salt modifier


//when a user provides their email when logging in, we can replicate the hash and search for the user in the database.
$user = User::where('username_lookup', DatabaseHashing::create($request->get("username"), $request->get("email")))->first();

常见问题解答

我可以手动哈希任意数据吗?

是的!您可以使用 DatabaseHashing::create() 全局外观手动对任何字符串进行哈希处理。

例如

    //hash with only application salt
    $hashedEmail = DatabaseHashing::create(Input::get('email'));

    //hash with application salt AND salt modifier
    $hashedEmail = DatabaseHashing::create(Input::get("email"), Input::get('password'));

我可以对所有模型数据哈希吗?

不!哈希过程是不可逆的,这意味着它应仅用于创建(假名)标识符,以便仍然可以在数据库中查找数据。如果您想加密数据,请使用类似 laravel-database-encryption 的软件包。

我应该对自增标识符哈希吗?

可能不是。如果数据库中存储的所有数据都是加密或散列的,那么数字标识符实际上就是匿名的(它实际上是假名)因此无法将任何可读数据与该标识符关联。还有其他原因不将数据库中的主键进行散列或加密,你可以在这里了解相关信息。

与laravel-database-encryption包的兼容性

默认情况下,这两个包将会冲突,但我们可以通过实现自己的setAttribute()方法来解决这个问题,该方法同时调用这两个包的实现。

class User extends Authenticatable
{
    use Notifiable, HasEncryptedAttributes, HasHashedAttributes {
        HasEncryptedAttributes::setAttribute as setEncryptedAttribute;
        HasHashedAttributes::setAttribute as setHashedAttribute;
    }

    protected $fillable = [
        'name', 'email', 'email_lookup', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    protected $encrypted = [
        'name', 'email',
    ];

    protected $hashing = [
        'email_lookup',
    ];

    /**
     * Overwrite the method so we can attempt to encrypt OR hash an
     * attribute without the traits colliding.
     *
     * @param string $key
     * @param mixed $value
     */
    public function setAttribute($key, $value)
    {
        $this->setEncryptedAttribute($key, $value); //attempt to encrypt the attribute

        $current = $this->attributes[$key] ?? null; //fetch the current value of the attribute
        if($current === $value) { //check to make sure the attribute wasn't modified (we will never hash an encrypted attribute)
            $this->setHashedAttribute($key, $value); //attempt to hash the attribute
        }
    }
}

如果这个方法需要在项目中的多个模型中使用,可以将其提取为单独的特质。同样的方法也可以用来使实现模型上的setAttribute()方法的任何包兼容。