learn.lianglianglee.com/专栏/透视HTTP协议/36 WAF:保护我们的网络服务.md.html
2022-05-11 19:04:14 +08:00

737 lines
27 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>36 WAF保护我们的网络服务.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/透视HTTP协议/00 开篇词To Be a HTTP Hero.md.html">00 开篇词To Be a HTTP Hero.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/01 时势与英雄HTTP的前世今生.md.html">01 时势与英雄HTTP的前世今生.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/02 HTTP是什么HTTP又不是什么.md.html">02 HTTP是什么HTTP又不是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/03 HTTP世界全览与HTTP相关的各种概念.md.html">03 HTTP世界全览与HTTP相关的各种概念.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/04 HTTP世界全览与HTTP相关的各种协议.md.html">04 HTTP世界全览与HTTP相关的各种协议.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html">05 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/06 域名里有哪些门道?.md.html">06 域名里有哪些门道?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/07 自己动手搭建HTTP实验环境.md.html">07 自己动手搭建HTTP实验环境.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/08 键入网址再按下回车,后面究竟发生了什么?.md.html">08 键入网址再按下回车,后面究竟发生了什么?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/09 HTTP报文是什么样子的.md.html">09 HTTP报文是什么样子的.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/10 应该如何理解请求方法?.md.html">10 应该如何理解请求方法?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/11 你能写出正确的网址吗?.md.html">11 你能写出正确的网址吗?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/12 响应状态码该怎么用?.md.html">12 响应状态码该怎么用?.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/13 HTTP有哪些特点.md.html">13 HTTP有哪些特点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/14 HTTP有哪些优点又有哪些缺点.md.html">14 HTTP有哪些优点又有哪些缺点.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/15 海纳百川HTTP的实体数据.md.html">15 海纳百川HTTP的实体数据.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/16 把大象装进冰箱HTTP传输大文件的方法.md.html">16 把大象装进冰箱HTTP传输大文件的方法.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/17 排队也要讲效率HTTP的连接管理.md.html">17 排队也要讲效率HTTP的连接管理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/18 四通八达HTTP的重定向和跳转.md.html">18 四通八达HTTP的重定向和跳转.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/19 让我知道你是谁HTTP的Cookie机制.md.html">19 让我知道你是谁HTTP的Cookie机制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/20 生鲜速递HTTP的缓存控制.md.html">20 生鲜速递HTTP的缓存控制.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/21 良心中间商HTTP的代理服务.md.html">21 良心中间商HTTP的代理服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/22 冷链周转HTTP的缓存代理.md.html">22 冷链周转HTTP的缓存代理.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/23 HTTPS是什么SSLTLS又是什么.md.html">23 HTTPS是什么SSLTLS又是什么.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/24 固若金汤的根本(上):对称加密与非对称加密.md.html">24 固若金汤的根本(上):对称加密与非对称加密.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/25 固若金汤的根本(下):数字签名与证书.md.html">25 固若金汤的根本(下):数字签名与证书.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/26 信任始于握手TLS1.2连接过程解析.md.html">26 信任始于握手TLS1.2连接过程解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/27 更好更快的握手TLS1.3特性解析.md.html">27 更好更快的握手TLS1.3特性解析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/28 连接太慢该怎么办HTTPS的优化.md.html">28 连接太慢该怎么办HTTPS的优化.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/29 我应该迁移到HTTPS吗.md.html">29 我应该迁移到HTTPS吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/30 时代之风HTTP2特性概览.md.html">30 时代之风HTTP2特性概览.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/31 时代之风HTTP2内核剖析.md.html">31 时代之风HTTP2内核剖析.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/32 未来之路HTTP3展望.md.html">32 未来之路HTTP3展望.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/33 我应该迁移到HTTP2吗.md.html">33 我应该迁移到HTTP2吗.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/34 Nginx高性能的Web服务器.md.html">34 Nginx高性能的Web服务器.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/35 OpenResty更灵活的Web服务器.md.html">35 OpenResty更灵活的Web服务器.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/透视HTTP协议/36 WAF保护我们的网络服务.md.html">36 WAF保护我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/37 CDN加速我们的网络服务.md.html">37 CDN加速我们的网络服务.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/38 WebSocket沙盒里的TCP.md.html">38 WebSocket沙盒里的TCP.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/39 HTTP性能优化面面观.md.html">39 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/40 HTTP性能优化面面观.md.html">40 HTTP性能优化面面观.md.html</a>
</li>
<li>
<a href="/专栏/透视HTTP协议/结束语 做兴趣使然的Hero.md.html">结束语 做兴趣使然的Hero.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>36 WAF保护我们的网络服务</h1>
<p>在前些天的“安全篇”里,我谈到了 HTTPS它使用了 SSL/TLS 协议,加密整个通信过程,能够防止恶意窃听和窜改,保护我们的数据安全。</p>
<p>但 HTTPS 只是网络安全中很小的一部分,仅仅保证了“通信链路安全”,让第三方无法得知传输的内容。在通信链路的两端,也就是客户端和服务器,它是无法提供保护的。</p>
<p>因为 HTTP 是一个开放的协议Web 服务都运行在公网上,任何人都可以访问,所以天然就会成为黑客的攻击目标。</p>
<p>而且黑客的本领比我们想象的还要大得多。虽然不能在传输过程中做手脚,但他们还可以“假扮”成合法的用户访问系统,然后伺机搞破坏。</p>
<h2>Web 服务遇到的威胁</h2>
<p>黑客都有哪些手段来攻击 Web 服务呢?我给你大概列出几种常见的方式。</p>
<p>第一种叫“<strong>DDoS</strong>”攻击distributed denial-of-service attack有时候也叫“洪水攻击”。</p>
<p>黑客会控制许多“僵尸”计算机向目标服务器发起大量无效请求。因为服务器无法区分正常用户和黑客只能“照单全收”这样就挤占了正常用户所应有的资源。如果黑客的攻击强度很大就会像“洪水”一样对网站的服务能力造成冲击耗尽带宽、CPU 和内存,导致网站完全无法提供正常服务。</p>
<p>“DDoS”攻击方式比较“简单粗暴”虽然很有效但不涉及 HTTP 协议内部的细节,“技术含量”比较低,不过下面要说的几种手段就不一样了。</p>
<p>网站后台的 Web 服务经常会提取出 HTTP 报文里的各种信息,应用于业务,有时会缺乏严格的检查。因为 HTTP 报文在语义结构上非常松散、灵活URI 里的 query 字符串、头字段、body 数据都可以任意设置,这就带来了安全隐患,给了黑客“<strong>代码注入</strong>”的可能性。</p>
<p>黑客可以精心编制 HTTP 请求报文,发送给服务器,服务程序如果没有做防备,就会“上当受骗”,执行黑客设定的代码。</p>
<p><strong>SQL 注入</strong>SQL injection应该算是最著名的一种“代码注入”攻击了它利用了服务器字符串拼接形成 SQL 语句的漏洞,构造出非正常的 SQL 语句,获取数据库内部的敏感信息。</p>
<p>另一种“<strong>HTTP 头注入</strong>”攻击的方式也是类似的原理它在“Host”“User-Agent”“X-Forwarded-For”等字段里加入了恶意数据或代码服务端程序如果解析不当就会执行预设的恶意代码。</p>
<p>在之前的[第 19 讲]里,也说过一种利用 Cookie 的攻击手段,“<strong>跨站脚本</strong>XSS攻击它属于“JS 代码注入”,利用 JavaScript 脚本获取未设防的 Cookie。</p>
<h2>网络应用防火墙</h2>
<p>面对这么多的黑客攻击手段,我们应该怎么防御呢?</p>
<p>这就要用到“<strong>网络应用防火墙</strong>Web Application Firewall简称为“<strong>WAF</strong>”。</p>
<p>你可能对传统的“防火墙”比较熟悉。传统“防火墙”工作在三层或者四层,隔离了外网和内网,使用预设的规则,只允许某些特定 IP 地址和端口号的数据包通过,拒绝不符合条件的数据流入或流出内网,实质上是<strong>一种网络数据过滤设备</strong></p>
<p>WAF 也是一种“防火墙”,但它工作在七层,看到的不仅是 IP 地址和端口号,还能看到整个 HTTP 报文,所以就能够对报文内容做更深入细致的审核,使用更复杂的条件、规则来过滤数据。</p>
<p>说白了WAF 就是一种“<strong>HTTP 入侵检测和防御系统</strong>”。</p>
<p><img src="assets/e8369d077454e5b92e3722e7090551a3.png" alt="img" /></p>
<p>WAF 都能干什么呢?</p>
<p>通常一款产品能够称为 WAF要具备下面的一些功能</p>
<ul>
<li>IP 黑名单和白名单,拒绝黑名单上地址的访问,或者只允许白名单上的用户访问;</li>
<li>URI 黑名单和白名单,与 IP 黑白名单类似,允许或禁止对某些 URI 的访问;</li>
<li>防护 DDoS 攻击,对特定的 IP 地址限连限速;</li>
<li>过滤请求报文,防御“代码注入”攻击;</li>
<li>过滤响应报文,防御敏感信息外泄;</li>
<li>审计日志,记录所有检测到的入侵操作。</li>
</ul>
<p>听起来 WAF 好像很高深,但如果你理解了它的工作原理,其实也不难。</p>
<p>它就像是平时编写程序时必须要做的函数入口参数检查,拿到 HTTP 请求、响应报文,用字符串处理函数看看有没有关键字、敏感词,或者用正则表达式做一下模式匹配,命中了规则就执行对应的动作,比如返回 403/404。</p>
<p>如果你比较熟悉 Apache、Nginx、OpenResty可以自己改改配置文件写点 JS 或者 Lua 代码,就能够实现基本的 WAF 功能。</p>
<p>比如说,在 Nginx 里实现 IP 地址黑名单可以利用“map”指令从变量 $remote_addr 获取 IP 地址,在黑名单上就映射为值 1然后在“if”指令里判断</p>
<pre><code>map $remote_addr $blocked {
default 0;
&quot;1.2.3.4&quot; 1;
&quot;5.6.7.8&quot; 1;
}
if ($blocked) {
return 403 &quot;you are blocked.&quot;;
}
</code></pre>
<p>Nginx 的配置文件只能静态加载,改名单必须重启,比较麻烦。如果换成 OpenResty 就会非常方便,在 access 阶段进行判断IP 地址列表可以使用 cosocket 连接外部的 Redis、MySQL 等数据库,实现动态更新:</p>
<pre><code>local ip_addr = ngx.var.remote_addr
local rds = redis:new()
if rds:get(ip_addr) == 1 then
ngx.exit(403)
end
</code></pre>
<p>看了上面的两个例子,你是不是有种“跃跃欲试”的冲动了,想自己动手开发一个 WAF</p>
<p>不过我必须要提醒你,在网络安全领域必须时刻记得“<strong>木桶效应</strong>”(也叫“短板效应”)。网站的整体安全不在于你加固的最强的那个方向,而是在于你可能都没有意识到的“短板”。黑客往往会“避重就轻”,只要发现了网站的一个弱点,就可以“一点突破”,其他方面的安全措施也就都成了“无用功”。</p>
<p>所以,使用 WAF 最好“<strong>不要重新发明轮子</strong>”,而是使用现有的、比较成熟的、经过实际考验的 WAF 产品。</p>
<h2>全面的 WAF 解决方案</h2>
<p>这里我就要“隆重”介绍一下 WAF 领域里的最顶级产品了ModSecurity它可以说是 WAF 界“事实上的标准”。</p>
<p>ModSecurity 是一个开源的、生产级的 WAF 工具包,历史很悠久,比 Nginx 还要大几岁。它开始于一个私人项目,后来被商业公司 Breach Security 收购,现在则是由 TrustWave 公司的 SpiderLabs 团队负责维护。</p>
<p>ModSecurity 最早是 Apache 的一个模块,只能运行在 Apache 上。因为其品质出众,大受欢迎,后来的 2.x 版添加了 Nginx 和 IIS 支持,但因为底层架构存在差异,不够稳定。</p>
<p>所以,这两年 SpiderLabs 团队就开发了全新的 3.0 版本,移除了对 Apache 架构的依赖,使用新的“连接器”来集成进 Apache 或者 Nginx比 2.x 版更加稳定和快速,误报率也更低。</p>
<p>ModSecurity 有两个核心组件。第一个是“<strong>规则引擎</strong>它实现了自定义的“SecRule”语言有自己特定的语法。但“SecRule”主要基于正则表达式还是不够灵活所以后来也引入了 Lua实现了脚本化配置。</p>
<p>ModSecurity 的规则引擎使用 C++11 实现,可以从<a href="https://github.com/SpiderLabs/ModSecurity">GitHub</a>上下载源码,然后集成进 Nginx。因为它比较庞大编译很费时间所以最好编译成动态模块在配置文件里用指令“load_module”加载</p>
<pre><code>load_module modules/ngx_http_modsecurity_module.so;
</code></pre>
<p>只有引擎还不够,要让引擎运转起来,还需要完善的防御规则,所以 ModSecurity 的第二个核心组件就是它的“<strong>规则集</strong>”。</p>
<p>ModSecurity 源码提供一个基本的规则配置文件“<strong>modsecurity.conf-recommended</strong>使用前要把它的后缀改成“conf”。</p>
<p>有了规则集,就可以在 Nginx 配置文件里加载,然后启动规则引擎:</p>
<pre><code>modsecurity on;
modsecurity_rules_file /path/to/modsecurity.conf;
</code></pre>
<p>“modsecurity.conf”文件默认只有检测功能不提供入侵阻断这是为了防止误杀误报把“SecRuleEngine”后面改成“On”就可以开启完全的防护</p>
<pre><code>#SecRuleEngine DetectionOnly
SecRuleEngine On
</code></pre>
<p>基本的规则集之外ModSecurity 还额外提供一个更完善的规则集,为网站提供全面可靠的保护。这个规则集的全名叫“<strong>OWASP ModSecurity 核心规则集</strong>Open Web Application Security Project ModSecurity Core Rule Set因为名字太长了所以有时候会简称为“核心规则集”或者“CRS”。</p>
<p>CRS 也是完全开源、免费的,可以从 GitHub 上下载:</p>
<pre><code>git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git
</code></pre>
<p>其中有一个“<strong>crs-setup.conf.example</strong>”的文件,它是 CRS 的基本配置可以用“Include”命令添加到“modsecurity.conf”里然后再添加“rules”里的各种规则。</p>
<pre><code>Include /path/to/crs-setup.conf
Include /path/to/rules/*.conf
</code></pre>
<p>你如果有兴趣可以看一下这些配置文件里面用“SecRule”定义了很多的规则基本的形式是“SecRule 变量 运算符 动作”。不过 ModSecurity 的这套语法“自成一体”,比较复杂,要完全掌握不是一朝一夕的事情,我就不详细解释了。</p>
<p>另外ModSecurity 还有强大的审计日志Audit Log功能记录任何可疑的数据供事后离线分析。但在生产环境中会遇到大量的攻击日志会快速增长消耗磁盘空间而且写磁盘也会影响 Nginx 的性能,所以一般建议把它关闭:</p>
<pre><code>SecAuditEngine off #RelevantOnly
SecAuditLog /var/log/modsec_audit.log
</code></pre>
<h2>小结</h2>
<p>今天我们一起学习了“网络应用防火墙”,也就是 WAF使用它可以加固 Web 服务。</p>
<ol>
<li>Web 服务通常都运行在公网上容易受到“DDoS”、“代码注入”等各种黑客攻击影响正常的服务所以必须要采取措施加以保护</li>
<li>WAF 是一种“HTTP 入侵检测和防御系统”,工作在七层,为 Web 服务提供全面的防护;</li>
<li>ModSecurity 是一个开源的、生产级的 WAF 产品,核心组成部分是“规则引擎”和“规则集”,两者的关系有点像杀毒引擎和病毒特征库;</li>
<li>WAF 实质上是模式匹配与数据过滤,所以会消耗 CPU增加一些计算成本降低服务能力使用时需要在安全与性能之间找到一个“平衡点”。</li>
</ol>
<h2>课下作业</h2>
<ol>
<li>HTTPS 为什么不能防御 DDoS、代码注入等攻击呢</li>
<li>你还知道有哪些手段能够抵御网络攻击吗?</li>
</ol>
<p>欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。</p>
<p><img src="assets/b9e48b813c98bb34b4b433b7326ace24.png" alt="unpreview" /></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/透视HTTP协议/35 OpenResty更灵活的Web服务器.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/透视HTTP协议/37 CDN加速我们的网络服务.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997d31e9ef3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>