2017-03-16 98 views
16

几天以来,我一直在为我的单页应用程序寻找安全的身份验证和会话管理机制。从许多教程和博客文章中可以看出,关于SPA和身份验证,将JWT存储在localStorage或常规Cookie中似乎是最常见的方法,但it's simply not a good idea to use JWTs for sessions因此它不适用于此应用程序。使用HttpOnly基于cookie的身份验证和会话管理的单页应用程序

要求

  • 登录应该是revokable。例如,如果在用户的帐户上检测到可疑活动,应该可以立即撤销该用户的访问权限并要求重新登录。类似地,密码重置等操作应撤销所有现有登录。
  • 身份验证应通过Ajax进行。之后不应该发生浏览器重定向(“硬”重定向)。所有的导航应该在SPA内进行。
  • 一切都应该跨域工作。 SPA将在www.domain1.com上,服务器将在www.domain2.com上。
  • JavaScript应该无法访问服务器发送的敏感数据,例如会话ID。这是为了防止恶意脚本可以从常规cookie,localStorage或sessionStorage窃取令牌或会话ID的XSS攻击。

理想的机制似乎是使用HttpOnly包含会话ID的基于cookie的身份验证。该流程的工作是这样的:

  1. 用户到达一个登录页面,并提交自己的用户名和密码。
  2. 服务器对用户进行身份验证,并将会话ID作为HttpOnly响应cookie发送。
  3. SPA随后将此cookie包含在对服务器进行的后续XHR请求中。这似乎可以使用withCredentials选项。
  4. 向受保护端点发出请求时,服务器查找cookie。如果找到,它会交叉检查该数据库表的会话ID以确保该会话仍然有效。
  5. 当用户注销时,会话将从数据库中删除。用户下次到达网站时,SPA会收到401/403响应(因为会话已过期),然后将用户带到登录屏幕。

由于cookie具有HttpOnly标志,因此JavaScript将无法读取其内容,因此只要通过HTTPS传输它就可以避免攻击。

挑战

这里的具体问题,我碰上了。我的服务器被配置为处理CORS请求。认证用户之后,它正确地发送的cookie的响应:

HTTP/1.1 200 OK 
server: Cowboy 
date: Wed, 15 Mar 2017 22:35:46 GMT 
content-length: 59 
set-cookie: _myapp_key=SFMyNTYBbQAAABBn; path=/; HttpOnly 
content-type: application/json; charset=utf-8 
cache-control: max-age=0, private, must-revalidate 
x-request-id: qi2q2rtt7mpi9u9c703tp7idmfg4qs6o 
access-control-allow-origin: http://localhost:8080 
access-control-expose-headers: 
access-control-allow-credentials: true 
vary: Origin 

但是,浏览器不保存的Cookie(当我检查Chrome的本地饼干它不存在)。所以,当下面的代码运行:

context.axios.post(LOGIN_URL, creds).then(response => { 
    context.$router.push("/api/account") 
} 

和账户页面被创建:

created() { 
    this.axios.get(SERVER_URL + "/api/account/", {withCredentials: true}).then(response => { 
    //do stuff 
    } 
} 

此调用没有在标题中的cookie。因此服务器拒绝它。

GET /api/account/ HTTP/1.1 
Host: localhost:4000 
Connection: keep-alive 
Accept: application/json 
Origin: http://localhost:8080 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 
Referer: http://localhost:8080/ 
Accept-Encoding: gzip, deflate, sdch, br 
Accept-Language: en-US,en;q=0.8,tr;q=0.6 

我是否需要做一些特殊的事情来确保浏览器在登录响应中收到cookie后保存cookie?我读过的各种人士称,浏览器保存响应cookie只有当用户被重定向,但我不希望任何“硬”重定向,因为这是一个SPA。

有问题的SPA是写在Vue.js,但我想它适用于所有的温泉。我想知道人们如何处理这种情况。

其他的东西,我对这个话题阅读:

+0

嗨PHP只是验证!你找到这个问题的原因吗? – Yuriy

回答

0

有了证书控件设置和发送的cookie,所以一定要打开它时张贴到登录,所以返回的cookie保存在浏览器中。

1

我得到这个工作Vue.js 2凭据=真。从客户端站点设置凭据只是故事的一半。你需要从服务器设置响应头以及:

header("Access-Control-Allow-Origin: http://localhost:8080"); 
    header("Access-Control-Allow-Credentials: true"); 

不能使用通配符访问控制允许来源是这样的:

header("Access-Control-Allow-Origin: *"); 

当您指定的凭据:真头,你需要指定orgin。

正如你可以看到,这是一个PHP代码,您可以在模型或的NodeJS你使用任何服务器端脚本语言。

在VueJS我在main.js设置凭据=真这样的:

Vue.http.options.credentials = true 

在组件中,我成功地登录了用ajax:

<template> 
<div id="userprofile"> 
    <h2>User profile</h2> 
    {{init()}} 

</div> 
</template> 

<script> 
    export default { 
     name: 'UserProfile', 
     methods: { 
     init: function() { 


       // loggin in 
       console.log('Attempting to login'); 

      this.$http.get('https://localhost/api/login.php') 
      .then(resource => { 
      // logging response - Notice I don't send any user or password for testing purposes 

      }); 

      // check the user profile 

       console.log('Getting user profile'); 

       this.$http.get('https://localhost/api/userprofile.php') 
       .then(resource => { 
        console.log(resource.data); 
       }) 

     } 
    } 
    } 

</script> 

在服务器端,事情非常简单: 的login.php上套未做任何验证任何一个cookie(注:这是用于测试目的,不建议您在生产中使用此代码未经验证完成)

<?php 

header("Access-Control-Allow-Origin: http://localhost:8080"); 
header("Access-Control-Allow-Credentials: true"); 

$cookie = setcookie('user', 'student', time()+3600, '/', 'localhost', false , true); 

if($cookie){ 
    echo "Logged in"; 
}else{ 
    echo "Can't set a cookie"; 
} 

最后,用户配置文件。如果一个cookie =用户设置

<?php 

    header("Access-Control-Allow-Origin: http://localhost:8080"); 
    header("Access-Control-Allow-Credentials: true"); 


if(isset($_COOKIE['user'])){ 
    echo "Congratulations the user is ". $_COOKIE['user']; 

}else{ 
    echo "Not allowed to access"; 
} 

成功登录

Successfully logged in

相关问题