在我刚学会一点asp编程时就知道cookie了,当时照着书上的代码一通输入运行后,一切OK,就这样我自以为掌握了cookie,学javascript照样是一通代码运行成功,cookie到此为止应该是山穷水尽,就那么回事,后来又闻cookie怎么怎么不安全(具体怎么地不清楚)于是逢人说cookie就大呼危险,应该使用session云云.工作半年有余,因为老报错的验证码问题知道session离不开cookie,后来asp.net中的form认证又是cookie一手操办,到最近要在两个站点:一个asp一个asp.net需要实现状态共享,发现还是关于cookie....
为什么要cookie:
HTTP协议是一个无状态的协议,作为某个IE浏览器第一次访问某asp或aspx,在原则上说是没有任何区别的,为了标记张三李四等,asp或aspx无一例外想起了cookie,当你访问asp页面时就能有一个ASPSESSIONIDxxx=xxxx这样的cookie被要求写入你的IE,而访问这个站点其他页面时,你所发出的请求无一例外都包括cookies:ASPSesssionIDxxx=xxx,于是在asp里就可以通过Session(username) 获取当前登录的是"张三",当然Session(username) 是保存在服务器内存中的,在asp.net中Session可以保存到SQL服务器或专门的Session服务进程中,但是标识还是通过cookie来维持,而在Asp.net Form认证中更是直接将信息写到cookie中,不过asp.net中你可以选择加密cookie,不过cookie多数情况下只放置一个Username或者userId,需要注意的是加密与否都不能防止重复攻击(通过跨站点脚本获取cookie,再使用这个cookie去访问一些需要相应身份的资源--页面), 当然多数程序员不会傻到把一些敏感信息保存到没加密的cookie里,数据库跟Session会更合适,但是在基于B/S的应用下你很难找到除cookie外的方式来标识某个会话,asp.net可以通过url来标识状态,但是url似乎比cookie更容易暴露, 说到这里情况有点让人沮丧,不过在SSL环境下,多数B/S应用可以达到一个比较高的安全要求的.
使用cookie做事
经常的看到很多文章说,用cookie保存用户喜欢的颜色啊,搞个投票程序记录状态什么地,这其实搞歪了,cookie最好还是用来标记会话状态比较好,这样一来你就可以在不同的程序中保持会话状态(asp与asp.net),以及同一域名不同主机下保持状态(a1.domain.com跟a2.domain.com等),这些在需要扩充站点功能时能派上用场.
同样的Cookie
无论Asp或Asp.net 他们使用的cookie其实完全一样,由于语言与沟通问题曾经导致我草率的认为他们是不同的两个cookie.
一个完整的cookie 应该是 有个名字,接着有个叫Domain的属性,还要带个Path, 凡是这个三个属性相同的Cookie是同个cookie, 在 一般在asp程序里你会使用 Request.Cookies("xxx")="value",来设置一个cookie,但是这个cookie,在你使用http://www.xxx.com/,时跟http://xxx.com/访问时其输出的domain是不同的,因此,你在http://www.xxx.com/登录后,在ie中输入http://xxx.com/的页面时发现你已经不是登陆状态,原因就在于你没设置domain属性,IE在使用Get或Post请求数据时会附加跟域名domain相匹配的cookie.
因此你想在A.wow52.cn登录后,在B.wow52.cn同样处于登陆状态,也就是在访问B.wow52.cn上的页面时可以读到A.wow52.cn设置的cookie(username)你需要写入如下一段cookie (asp版)
response.Cookies("wow52UserCookie")="张三"
response.Cookies("wow52UserCookie").domain=".wow52.cn"
response.Cookies("wow52UserCookie").Expires="2009-12-1"
'//不设置Expires 属性 cookie默认在浏览器关闭后失效(内存cookie)
response.Cookies("wow52UserCookie").Path="/"
这样一翻设置后,你在B.wow52.cn中就可以读到这个"张三", Name,Domain, Path 三个属性来标识一个唯一的cookie, 而其中的Domain属性决定浏览器是否附加cookie信息给新请求的页面,不过你不要指望在http://www.wow52.cn/ 输出一个domain是.gyzs.net的cookie,让浏览器在请求http://www.gyzs.net/的页面时带上这个cookie, IE在出于安全的原因会明确拒绝这样的做法,想使用这样方式来实现多域名单点登录是行不通的.
清除一个cookie:
在用户退出时(注销)需要清除cookie,不过遗憾的是response.Cookies并没提供删除cookie的办法,唯一的做法是设置某个cookie过期,也就是设置Expires属性,代码看起来应该如下
response.Cookies("wow52UserCookie")="" '//设置成空字符
response.Cookies("wow52UserCookie").domain=".wow52.cn"
response.Cookies("wow52UserCookie").Expires="1990-1-1" '//1990年,现在是2009年不要发生时光倒转就好
response.Cookies("wow52UserCookie").Path="/"
Response.Redirect('/index.html')
这段代码会输出一个Set-cookie:..... 发送给浏览器(你需要一些代理软件来观察这些),浏览器在收到信息后就将这个cookie抛弃掉,同时Redirect迫使浏览器马上访问一个新页面,这个时候浏览器就不会发送名为wow52UserCookie的这个cookie了他过期了,只要IE不发送,那么对服务器的asp来说它就消失了,被删除了,我现在不知道你是"张三"还是"李四"了, 最后你如果看asp.net里的反编译代码,FormsAuthentication.SignOut()这句代码做的事情几乎一样(当然设置不同名称,domain,跟path,这个你可以在web.config里配置).
asp跟asp.net互通cookie:
几年前我也做过同样的测试,asp页中写个cookie,asp.net读出这个cookie, 由于一些社会自然原因,当时我用的是"安定法安定发"类似的中文数据,结果在asp.net中没读出来,或许是读出一堆乱码,于是我下了结论,asp,asp.net不能恭享cookie,这个想法直到2年后才发现自己的无知,在GB2312的asp页面下(asp pagecode="936"),你输出的cookie,asp会进行UrlEncode--采用GB2312编码, 这个在多数只使用asp的情况下没什么,asp会自动解编码,但是asp.net就不一样了,你必须使用Server.UrlDecode()才可以获取正常的内容,不过这个时候你的web.config设置是gb2312的,如果没设置或设置为utf-8,那么你就需要使用HttpUtility.UrlDecode(value,Encoding.GetEncoding("GB2312"))来解码了,另外建议只使用英文字母跟数字来设置cookie.Name属性,以免名称上也出现分歧. 反过来在asp.net写cookie,asp中读取,你需要做的是把cookie.value用UrlEncode编码下即可,同样注意下编码要互相对应.