使用基于HttpOnly cookie的单页应用程序进行身份验证和会话管理

时间:2017-03-16 02:49:55

标签: reactjs cookies vue.js session-cookies vuejs2

现在,我一直在为单页应用程序寻找安全的身份验证和会话管理机制。根据有关SPA和身份验证的众多教程和博客文章来判断,将JWT存储在localStorage或常规cookie中似乎是最常用的方法,但it's simply not a good idea to use JWTs for sessions因此它不适用于此应用程序。< / p>

要求

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

理想的机制似乎是使用包含会话ID的HttpOnly cookie进行基于cookie的身份验证。流程将如下工作:

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

    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,但我不想要任何&#34;硬&#34;重定向,因为这是一个SPA。

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

    我已经阅读过有关此主题的其他内容:

2 个答案:

答案 0 :(得分:3)

我使用凭证= true在Vue.js 2上工作。从客户端站点设置凭据只有故事的一半。您还需要从服务器设置响应标头:

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

您无法使用通配符进行Access-Control-Allow-Origin,如下所示:

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

当您指定凭证:true标头时,您需要指定orgin。

如您所见,这是一个PHP代码,您可以将其建模为NodeJS或您正在使用的任何服务器端脚本语言。

在VueJS中,我在main.js中设置了credentials = true:

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 on设置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";
}

最后,userprofile.php只验证是否设置了cookie = user

<?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

答案 1 :(得分:0)

使用凭据控制设置和发送cookie,因此请务必在发布到登录时将其打开,以便将返回的cookie保存在浏览器中。