本系列随笔是本人的学习笔记,初学阶段难免会有理解不当之处,错误之处恳请指正。转载请注明出处:https://www.cnblogs.com/itwhite/p/12267738.html。
简介:客户端存储,服务端使用
cookie 是一种早期的客户端存储机制,最初是针对服务端脚本设计使用的(由服务端发起 Set-Cookie,存储于客户端浏览器中,然后客户端每次发送请求时都带上 cookie 值,服务端通过 cookie 来识别用户)。
cookie 作为一种被服务端脚本使用的客户端存储机制,其工作过程如下图所示:
下面以一段简单的 PHP 服务端程序(foo.php)模拟上述过程:
<?php if (!isset($_COOKIE["foo"])) { setcookie("foo", "1234", time()+3600); // 服务端调用这个函数,在发送到客户端的响应头部信息中会添加一个 Set-Cookie 字段告诉客户端存储这个 cookie } ?>
从浏览器端打开这个页面,并进入开发者模式查看HTTP请求和响应,如下图所示:
从图中可以看到服务端响应报文头部会包含一个 Set-Cookie 字段(其内容正是我们在服务端程序中设置的),浏览器会自动存储这个 cookie,当我们下一次访问 foo.php 这个页面时,客户端的请求报文头部信息中会带上这个 cookie 发送给服务端,如下图所示:
客户端(JavaScript)中读写cookie
前面的示例中,cookie 的读、写都在服务端脚本中完成,实际上客户端脚本中也可以读写 cookie (客户端生成的 cookie 也会在下一次发起请求时发送至服务端)。
不过 JavaScript 并没有提供很友好的 API 来操作 cookie ,客户端中可以通过 document.cookie 属性(其值是一个字符串)来读写 cookie 。
示例一:读取 cookie
还是以前面的 foo.php 为例,在其后面加上客户端脚本,代码如下:
<?php if (!isset($_COOKIE["foo"])) { setcookie("foo", "1234", time()+3600); } ?> <script> alert(document.cookie); </script>
再次访问 foo.php 页面时,浏览器端会在弹出框中输出cookie的内容,如下图所示:
示例二:设置 cookie
直接赋值给 document.cookie,代码如下:
<script> document.cookie = "bar=5678;max-age=3600"; </script>
注意:上面的代码看起来像是覆盖了 document.cookie 原来的值,实际上不会,此处创建了一个新的 cookie (键名为 bar),原来的 foo 仍然存在,并且打印 document.cookie 时会同时输出 foo=1234; bar=5678 。
如何禁止客户端读取 cookie ?
从上面的示例可以看到,JavaScript 脚本也能读写 cookie,但是出于安全性考虑,有时候我们可能不希望通过服务端设置的 cookie 被客户端脚本读写。
本文第一节的示例中用到 PHP 的 setcookie() 方法中其实还可以传入更多的参数(只不过前面的示例给省略了):
setcookie(name, value, expire, path, domain, secure, httponly)
其最后一个参数 httponly 用于控制是否仅可以通过 HTTP 协议访问(默认为 false),若设置为 true 则 JavaScript 脚本就无法访问了,这样可以减少 XSS 攻击时的身份窃取行为,例如(修改 foo.php 代码):
<?php if (!isset($_COOKIE["foo"])) { setcookie("foo", "1234", time()+3600, "/", "", false, true); } ?>
然后再次访问 foo.php 页面,从开发者工具的 Application 标签的 Cookies 中,我们可以看到 foo 的 HttpOnly 标志已经设置成了 true ,如下图所示:
提示:当再次从 JavaScript 中读取 document.cookie 时就只能读到 bar 而不能读到 foo 了,清除某个站点的 cookie 也可以从上图中页面中进行操作 。
cookie 的有效期
当设置 cookie 不指定有效期时,其默认有效期为 session ,如下图所示:
这种 cookie 只能存活于 Web 浏览器的会话期间(相对于整个浏览器进程,而不是单个窗口),当重启浏览器后 bar 就不存在了,foo 只要还没过期就仍然存在。
如果想要延长 cookie 的有效期,就需要明确地指定 cookie 的有效期,方法如下:
- PHP 的 setcookie() 中第三个参数用于指定有效期,它的值是相对于1970年1月1日开始时的秒数;
- JavaScript 中使用 max-age 来指定相对于当前时间的最大存活秒数。
前面示例中都有用到,这里就不重复举例了。
cookie 的作用域
cookie 的作用域是通过“文档源”(domain)和“文档路径”(path)来确定的。
假设我们在设置 cookie 时没有指定 path 和 domain,那么会出现以下情况:
- 我们在 www.example.com/foo/index.php 中设置的 cookie,在 www.example.com/bar/index.php 中是不可以访问的,因为他们属于不同的路径,如果要想让后者能访问,我们可以将 path 设置成“/”。
- 我们在 www.example.com/foo/index.php 中设置的 cookie,在 www.example.com/foo/bar/index.php 中是可以访问的,因为后者是前者的子目录,反过来则不可以。
- 我们在 foo.example.com/index.php 中设置的 cookie,在 bar.example.com/index.php 中是不可以访问的,因为它们属于不同的子域,要想让它们共享,我们可以将 domain 设置为“.example.com”(注意前面的点号)同时将 path 设置为“/”。
完。