我刚刚创建了Vue + Laravel SPA登录名,但是不确定它是否足够安全。我是VUE的新手:)
我正在使用JWT身份验证。当用户输入凭据并提交表单时,Laravel端的Auth将返回带有令牌的用户模型。该用户存储在本地存储中。在我的Vue路由器中,我创建了在每个视图更改之前运行的中间件。这工作正常,但是数据库中没有与此用户相关的实际令牌。当我手动更改存储中的令牌时,我仍在传递中间件,因为不再检查令牌。它只是检查本地存储中是否存在...我应该将令牌存储在DB中并在每次视图更改时检查它吗?还是... ??
答案 0 :(得分:0)
听起来不安全,不:)
我从没使用过Laravel,所以我不能专门谈论它,但是我可以解释该过程是如何工作的。
在服务器中,您应该具有中间人或某种逻辑,可以读取令牌并验证其完整性。令牌本身只是具有三个组成部分的Base64字符串
如果您有令牌,那么它很容易读取有效负载,因为它只是Base64字符串。因此,仅阅读它还不够,您需要确保签名正确。
创建JWT令牌时,当服务器发出请求时,会秘密进行。服务器应验证签名,以确保这是一个有效的令牌。如果您没有机密,则无法验证签名。只有你应该拥有秘密。
这将阻止“我作为攻击者”发送带有伪造有效载荷的令牌。通过验证签名,您可以确保这是您创建的令牌,而不是我发送给您的网站的伪造令牌。
您也不应该将该令牌存储在本地存储中。本地存储绝不应该包含令牌或密码之类的信息,因为这只是每个人都可以访问的字典/地图。因此,我可以创建一个读取本地存储的网站,获取您创建的令牌,并且由于这是带有正确签名的令牌,因此我现在可以向您的网站发出请求。
我建议将JWT令牌存储在https上的httpOnly cookie中(安全:大多数环境下为true选项)。浏览器无法读取httpOnly cookie,只能读取服务器。
从VueJS应用向服务器发出请求时,例如保存服务器上的博客帖子
例如
methods: {
saveBlogPost() {
axios.post('/api/save', {
title: 'My blog title'
userId: 'bergur'
})
}
}
您的服务器永远不要读取从VueJS应用发送的userId。 JWT中间人应该检查JWT,验证其完整性,然后使用有效负载中的信息。
编辑:我回答了一篇有关保护VueJS应用程序安全的类似文章。您可以在这里找到它:VueJS Secure with Auth0 - How is it secure?
基本上:可以在客户端中存储有助于使用户界面有意义的信息,但是在进行实际工作(例如保存到数据库或获取某些私有数据)时,服务器应始终验证用户身份。
答案 1 :(得分:0)
保护服务器端路由很重要。我为此使用的解决方案是使用lcobucci/jwt
中的php jwt库Laravel
。
我将解释使用默认且更简单的方法JWT秘密策略,而不是私钥/公钥策略(例如RSA)。
无论您使用哪种框架进行JWT
身份验证的步骤都是相同的:
一个简单的服务器端实现将包括
jwt secret
环境变量对于这些步骤,创建一个JWT_SECRET
env变量。这将是一个很大的随机字符串。您可以使用任何random string generator for this。例如:
JWT_SECRET=bX7fsuHzOksB27Pwh31qmazMsalw4bchu7Ft1X4PMOhO23Zq8nwBKA0FZQOK
创建api sign-in
路由
Route::post('authenticate', 'AuthenticateController@signIn');
app/Http/Controllers/AuthenticateController.php
<?php
namespace App\Http\Controllers;
use App\Services\JWTService;
class AuthenticateController extends Controller
{
protected $jwt;
public function __construct(JWTService $jwt)
{
$this->jwt = $jwt;
}
public function signIn(Request $request){
$token = $this->jwt->createToken();
$response = response()->json([
'message' => StatusCode::$texts[StatusCode::HTTP_OK],
'data' => [ 'token' => (string)$token]
], StatusCode::HTTP_OK);
return $response;
}
}
app/Services/JWTService.php
<?php
namespace App\Services;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Token;
class JWTService
{
public function createToken($privilege = 'externalUser'){
// eval(\Psy\sh());
$signer = new Sha256();
$key = new Key(env('JWT_SECRET')); // vindo null
$time = time();
$token = (new Builder())->issuedBy($privilege)->expiresAt($time + 3600)->getToken($signer, $key);
//->withClaim('uid', 1) // Configures a new claim, called "uid"
return $token;
}
public function parseString($bearerToken) : Token {
return (new Parser())->parse($bearerToken);
}
public function verify($token){
$signer = new Sha256();
$key = new Key(env('JWT_SECRET'));
if(!$token->verify($signer, $key))
abort(401, 'Unauthorized access.');
return true;
}
}
要保护您的路线,请为所有传入请求(登录除外)添加中间件。使用jwt声明的授权逻辑将由您负责。
<?php
namespace App\Http\Middleware;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use OutOfBoundsException;
use BadMethodCallException;
use Closure;
class Authorization
{
public function handle($request, Closure $next)
{
try {
$bearerToken = $request->bearerToken();
if(!isset($bearerToken))
abort(401, 'Unauthorized access.');
$token = (new Parser())->parse($bearerToken); // Parses from a string
$signer = new Sha256();
$key = new Key(env('JWT_SECRET'));
if(!$token->verify($signer, $key))
abort(401, 'Unauthorized access.');
return $next($request);
} catch(OutOfBoundsException $e){
abort(401, 'Requested data is not configured.');
} catch(BadMethodCallException $e){
abort(403, 'Token not signed.');
}
}
// $token->getHeaders(); // Retrieves the token header
// $token->getClaims(); // Retrieves the token claims
// $token->getClaim('iss');
// $token->getClaim('exp');
}
将中间件添加到kernel.php
protected $routeMiddleware = [
...
'tokenAuth' => \App\Http\Middleware\Authorization::class
];
通过这种方式,您可以通过以下方式将中间件添加到routes/api.php
:
Route::group(['middleware' => 'tokenAuth'], function(){
Route::resource('user', 'UserController');
Route::resource('Foo', 'FooController');
}
我强烈建议您阅读Laravel docs和lcobucci/jwt,以更好地理解步骤以及如何使用内置的jwt claims
和Laravel
工具来获得安全良好的解决方案。< / p>