`

cookies(转帖)

阅读更多

Cookie技术是一个非常有争议的技术,自经诞生它就成了广大网络用户和Web开发人员的一个争论焦点。有一些网络用户,甚至包括一些资深的 Web专家也对它的产生和推广感到不满,这倒不是因为Cookie技术的功能太弱或别的技术性能上的原因,而仅仅是因为他们觉得Cookie的使用,对网 络用户的隐私构成了危害。因为Cookie是由Web服务器保存在用户浏览器上的小文本文件,它包含有关用户的信息(如身份识别号码、密码、用户在Web 站点上购物的方式或用户访问该站点的次数)。

那么Cookie技术究竟怎样呢?是否真的给网络用户带来了个人隐私的危害呢?还是让我们看了下面的内容,再做回答吧。

(1)Cookie技术简介

在WEB 技术发展史上,Cookie技术的出现是一个重大的变革。最先是Netscape在它的Netscape Navigator 浏览器中引入了Cookie技术,从那时起,World Wide Web 协会就开始支持Cookie标准。以后又经过微软的大力推广(因为微软的IIS Web服务器所采用的ASP技术很大程度的使用了Cookier技术),即在微软的Internet Explorer浏览器中完全支持Cookie技术。到现在,绝大多数的浏览器都支持Cookie技术,或者至少兼容Cookie技术的使用。

1)什么是Cookie?

按 照Netscape官方文档中的定义,Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie是由Web服务器 保存在用户浏览器上的小广西文件,它可以包含有关用户的信息(如身份识别号码、密码、用户在Web站点购物的方式或用户访问该站点的次数)。无论何时用户 链接到服务器,Web站点都可以访问Cookie信息。

通俗地讲,浏览器用一个或多个限定的文件来支持Cookie。这些文件在使用 Windows操作系统的机器上叫做Cookie文件,在Macintosh机器上叫做magic Cookie 文件,这些文件被网站用来在上面存储Cookie数据。网站可以在这些Cookie文件中插入信息,这样对有些网络用户就有些副作用。有些用户认为这造成 了对个人隐私的侵犯,更糟的是,有些人认为Cookie是对个人空间的侵占,而且会对用户的计算机带来安全性的危害。

目前有些 Cookie是临时的,另一些则是持续的。临时的Cookie只在浏览器上保存一段规定的时间,一旦超过规定的时间该Cookie就会被系统清除。例如在 PHP中Cookie被用来跟踪用户进程直到用户离开网站。持续的Cookie则保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调 用。

在Cookie文件中保存Cookie,一些用户会过分地认为这将带来很大的问题。主要是有些用户担心Cookie会跟踪用户网 上冲浪的习惯,譬如用户喜爱到那些类型的站点、爱从事些什么活动等。害怕这种个人信息一旦落入一些别有用心的家伙手中,那么个人也就可能成为一大堆广告垃 圾的对象,甚至遭到意外的损害。不过,这种担心压根儿不会发生,因为网站以外的用户是无法跨过网站来获得Cookie信息的。所以想以这种目的来应用 Cookie是不可能的。不过,由于一些用户错误的理解以及“以讹传讹”,一些浏览器开发商别无选择,只好作出相识的响应(例如Netscape Navigator4.0和Internet Explorer3.0都提供了屏蔽Cookie的选项)。

对Cookie技术期待了 这么久的结果是,迫使许多浏览器开发商在它们的浏览器中提供了对Cookie的灵活性控制功能。例如,目前的两大主流浏览器Netscape Navigator 和 Internet Explorer是这样处理Cookie的:Netscape Navigator4.0不但可以接受Cookie进行警告,而且还可以屏蔽掉Cookie;InternetExplorer3.0也可以屏蔽 Cookie,但在Internet Explorer4.0中就只能进行接受警告而没有提供屏蔽选项,不过在Internet Explorer4.0之后的更新版本中又加入了屏蔽Cookie的功能选项。

此外,很多最新的技术甚至已经可以在不能屏蔽 Cookie的浏览器上进行Cookie的屏蔽了。例如,可以通过将Cookie文件设置成不同的类型来限制Cookie的使用。但是,非常不幸地是,要 是你想完全屏蔽Cookie的话,肯定会因此拒绝许多的站点页面。因为当今已经有许多Web站点开发人员爱上了Cookie技术的强大功能,例如 Session对象的使用就离不开Cookie的支持。

尽管今天仍有一些网络用户对于Cookie的争论乐此不倦,但是对于绝大多数的网络用户来说还是倾向于接受Cookie的。因此,我们尽可以放心地使用Cookie技术来开发我们的WEB页面。

2)Cookie是怎样工作的?

要 了解Cookie,必不可少地要知道它的工作原理。一般来说,Cookie通过HTTP Headers从服务器端返回到浏览器上。首先,服务器端在响应中利用Set-Cookie header来创建一个Cookie,然后,浏览器在它的请求中通过Cookie header包含这个已经创建的Cookie,并且反它返回至服务器,从而完成浏览器的论证。

例如,我们创建了一个名字为login 的Cookie来包含访问者的信息,创建Cookie时,服务器端的Header如下面所示,这里假设访问者的注册名是“Michael Jordan”,同时还对所创建的Cookie的属性如path、domain、expires等进行了指定。

Set-Cookie:login=Michael Jordan;path=/;domain=msn.com;
expires=Monday,01-Mar-99 00:00:01 GMT

上面这个Header会自动在浏览器端计算机的Cookie文件中添加一条记录。浏览器将变量名为“login”的Cookie赋值为“Michael Jordon”。注意,在实际传递过程中这个Cookie的值是经过了URLEncode方法的URL编码操作的。
这个含有Cookie值的HTTP Header被保存到浏览器的Cookie文件后,Header就通知浏览器将Cookie通过请求以忽略路径的方式返回到服务器,完成浏览器的认证操作。

此 外,我们使用了Cookie的一些属性来限定该Cookie的使用。例如Domain属性能够在浏览器端对Cookie发送进行限定,具体到上面的例子, 该Cookie只能传达室到指定的服务器上,而决不会跑到其他的如www.hp.com的Web站点上去。Expires属性则指定了该Cookie保存 的时间期限,例如上面的Cookie在浏览器上只保存到1999年3月1日1秒。当然,如果浏览器上Cookie太多,超过了系统所允许的范围,浏览器将 自动对它进行删除。至于属性Path,用来指定Cookie将被发送到服务器的哪一个目录路径下。

说明:浏览器创建了一个Cookie后,对于每一个针对该网站的请求,都会在Header中带着这个Cookie;不过,对于其他网站的请求Cookie是绝对不会跟着发送的。而且浏览器会这样一直发送,直到Cookie过期为止。

 

上一部分讲了有关Cookie的技术背景,这部分来说说在PHP里如何设置、使用、删除Cookie,及Cookie的一些限制。PHP对Cookie支持是透明的,用起来非常方便。

1、设置Cookie

PHP用SetCookie函数来设置Cookie。必须注意的一点是:Cookie是HTTP协议头的一部分,用于浏览器和服务器之间传递信息,所以必须在任何属于HTML文件本身的内容输出之前调用Cookie函数。
SetCookie函数定义了一个Cookie,并且把它附加在HTTP头的后面,SetCookie函数的原型如下:
int SetCookie(string name, string value, int expire, string path, string domain, int secure);
除 了name之外所有的参数都是可选的。value,path,domain三个参数可以用空字符串代换,表示没有设置;expire 和 secure两个参数是数值型的,可以用0表示。expire参数是一个标准的Unix时间标记,可以用time()或mktime()函数取得,以秒为 单位。secure参数表示这个Cookie是否通过加密的HTTPS协议在网络上传输。
当前设置的Cookie不是立即生效的,而是要等到下一个页面时才能看到.这是由于在设置的这个页面里Cookie由服务器传递给客户浏览器,在下一个页面浏览器才能把Cookie从客户的机器里取出传回服务器的原因。
在同一个页面设置Cookie,实际是从后往前,所以如果要在插入一个新的Cookie之前删掉一个,你必须先写插入的语句,再写删除的语句,否则可能会出现不希望的结果。
来看几个例子:
简单的:
SetCookie("MyCookie", "Value of MyCookie");
带失效时间的:
SetCookie("WithExpire", "Expire in 1 hour", time()+3600);//3600秒=1小时
什么都有的:
SetCookie("FullCookie", "Full cookie value", time()+3600, "/forum", ".phpuser.com", 1);

这 里还有一点要说明的,比如你的站点有几个不同的目录,那么如果只用不带路径的Cookie的话,在一个目录下的页面里设的Cookie在另一个目录的页面 里是看不到的,也就是说,Cookie是面向路径的。实际上,即使没有指定路径,WEB服务器会自动传递当前的路径给浏览器的,指定路径会强制服务器使用 设置的路径。解决这个问题的办法是在调用SetCookie时加上路径和域名,域名的格式可以是“www.phpuser.com”,也可是 “.phpuser.com”。
SetCookie函数里表示value的部分,在传递时会自动被encode,也就是说,如果value的 值是“test value”在传递时就变成了“test%20value”,跟URL的方法一样。当然,对于程序来说这是透明的,因为在PHP接收Cookie的值时会 自动将其decode。
如果要设置同名的多个Cookie,要用数组,方法是:
SetCookie("CookieArray[]", "Value 1");
SetCookie("CookieArray[]", "Value 2");

SetCookie("CookieArray[0]", "Value 1");
SetCookie("CookieArray[1]", "Value 2");

2、接收和处理Cookie

PHP对Cookie的接收和处理的支持非常好,是完全自动的,跟FORM变量的原则一样,特别简单。
比 如设置一个名为MyCookier的Cookie,PHP会自动从WEB服务器接收的HTTP头里把它分析出来,并形成一个与普通变量一样的变量,名为$ myCookie,这个变量的值就是Cookie的值。数组同样适用。另外一个办法是引用PHP的全局变量$HTTP_COOKIE_VARS数组。
分别举例如下:(假设这些都在以前的页面里设置过了,并且仍然有效)
echo $MyCookie;
echo $CookieArray[0];
echo count($CookieArray);
echo $HTTP_COOKIE_VARS["MyCookie"];
就这么简单。

3、删除Cookie

要删除一个已经存在的Cookie,有两个办法:
一是调用只带有name参数的SetCookie,那么名为这个name的Cookie将被从关系户机上删掉;另一个办法是设置Cookie的失效时间为time()或time()-1,那么这个Cookie在这个页面的浏览完之后就被删除了(其实是失效了)。
要注意的是,当一个Cookie被删除时,它的值在当前页在仍然有效的。

4、使用Cookie的限制

首先是必须在HTML文件的内容输出之前设置;
其 次不同的浏览器对Cookie的处理不一致辞,且有时会出现错误的结果。比如:MS IE+SERVICE PACK 1不能正确处理带域名和路径的Cookie,Netscape Communicator 4.05和MS IE 3.0不能正确处理不带路径和时间的Cookie。至于MS IE 5 好象不能处理带域名、路径和时间的Cookie。这是我在设计本站的页面时发现的。
第三个限制是在客户端的。一个浏览器能创建的Cookie数量最多为30个,并且每个不能超过4KB,每个WEB站点能设置的Cookie总数不能超过20个。


关于Cookie的话题,就说到这儿了。

(由于Cookie最初由Netscape定义的,所以附上Netscape公司关于Cookie的官方原始定义的网址:http://www.netscape.com/newsref/std/cookie_spec.html

现在有很多社区网为了方便网友浏览,都使用了cookie技术以避免多次输入密码


现在有很多社区网为了方便网友浏览,都使用了cookie技术以避免多次输入密码(就如the9
和vr),所以只要对服务器递交给用户的cookie进行改写就可以达到欺骗服务程序的目的。


COOKIE欺骗原理
按照浏览器的约定,只有来自同一域名的cookie才可以读写,而cookie只是浏览器的,对通
讯协议无影响,所以要进行cookie欺骗可以有多种途径:
1、跳过浏览器,直接对通讯数据改写
2、修改浏览器,让浏览器从本地可以读写任意域名cookie
3、使用签名脚本,让浏览器从本地可以读写任意域名cookie(有安全问题)
4、欺骗浏览器,让浏览器获得假的域名
其中:
方法1、2需要较专业的编程知识,对普通用户不太合适。
方法3的实现有2种方法:
1、直接使用签名脚本,不需要签名验证,但是产生很严重的安全问题,因为大家都要上网
的,如果这样做你的硬盘文件就……
2、对脚本进行签名后再使用签名脚本,但是需要专用的数字签名工具,对普通用户也不合
适。
方法4看样子应该是最合适的了,域名欺骗很简单,也不需要什么工具(当然如果你的机器
装有web服务器那更好了),下面我以the9为例,以这种方法为基础,阐述一下cookie欺骗的
过程(下文中提到的任何服务端的bug,the9都已经做了改进,所以本文对the9无安全方面的
影响):

注:我们讨论的cookie是那种不会在硬盘的cookie文件里留下踪迹的cookie,就是那种只在
浏览器生存周期内(会话)产生的cookie,如果浏览器关闭(会话结束)那么这个cookie就
被删了! 

COOKIE欺骗实战
the9在登陆的时候会返回3个cookie(这可把浏览器的警告cookie选项打开时看到):
cgl_random(随即序列号):登陆识别的记号
cgl_loginname(登陆名):身份的识别记号
cgl_areaid(小区号):你居住的小区号码
只要把cgl_loginname填入正确的登陆名,再对cgl_random进行修改,就可以达到欺骗服务程
序的目的。

一般欺骗php程序的字符串为:
1'or'1'='1
把这个填入cgl_random,服务程序就被欺骗了!
因为服务程序不太可能对cookie进行语法检查(the9现在改进了),那么把这个字符串填入
,就可以成功的欺骗对方程序,而达到突破的目的了!

现在的问题是,如何使浏览器把这个我改过的cookie返回给the9?
看一看the9的域名吧:http://www.the9.com/,而浏览器的cookie警告已经告诉了我们这3
个cookie会返回给有.the9.com这个域名的服务器,哎?我的机器上正好有web服务器,那么
动手吧!
先编一个设置cookie的html,就叫cookie.htm吧,然后把这个cookie放进web目录,这样还不
行,因为我的机器的域名没设,那么设置host的名字,可是如果在网络设置中进行设置的话
,机器要重启动的,还是想想别的简单的办法吧!
然后我们应该编辑hosts文件,这个文件应该在windows目录下,你有可能找不到它,但是如
果你找到了hosts.sam文件,那么把它后面的扩展名去掉,就是我们要的文件了!
编辑hosts文件,填入以下一行:
127.0.0.1 www0.the9.com
解释一下,127.0.0.1是本机的lo地址,可以用做web地址,而www0.the9.com就是我们欺骗产
生的域名。
然后在浏览器中输入http://www0.the9.com/cookie.htm,看,页面出来了,快设置cookie吧

直接访问http;//www.the9.com/main.htm看看,不错吧!

但是不是所有的网友都有自己的web服务器啊!那怎么办呢?
其实如果你有个人主页的话,也可以达到cookie欺骗的目的,比如某个个人主页的服务器的
ip地址是1.2.3.4,先上传cookie.htm文件,再编辑hosts文件:
1.2.3.4 www0.the9.com
然后访问http://www0.the9.com/***/cookie.htm,其中***是你个人主页的地址目录。

对了我作了个工具在我的主页上,现在公开一下,http://home.etang.com/fsl/9the/,大家
知道该怎么做了吧?嘿嘿,不过你那样设置是没有用的,要这样编辑hosts:
etang的ip www.the9.com
the9的ip www0.the9.com
为什么要这样呢?我等会会告诉大家的



继续the9的cookie讨论,还有2个cookie:
cgl_mainshowinfo(个人信息)
cgl_showinfo_changed(意义不知)
由于第二个cookie不知道是什么,所以就讨论第一个。
第一个cookie存放着你在the9的名字、称号、居住的小区、街道、是否有工作、星级、门牌
号等的信息(目前只知道这些,其余的信息不知其意义,具体格式就让给大家去分析了),
但是中文都escape过了,如果你用的不是netscpae而是ie的话,不能用unescape得知其信息
,因为ie对双字节采用unicode而不采用ascii,如果哪天the9也支持unicode就好了!:),
但是其他网站站长注意了,你们可通过cgi的形式把这些the9居民信息抓过来实现数据共享!
哈哈……,如果你们真要这么做,就只有使用签名脚本了,总不能让别人编辑hosts吧(不过
得注意版权哦!)?

ie的cookie漏洞:
如果你用的是ie的话,由于ie本身的漏洞,你大可不必编辑hosts,就可以同样做到读写别的
域名的cookie,你可以使用以下的方法欺骗ie(具体的可以去www.cookiecentral.com看看)

假设你的主页文件为http://a.com/cookie.htm,
使用以下url: http://a%2Ecom%2Fcookie%2Ehtm%3F.the9.com
如果直接输在浏览器地址栏里不行,就作个script,把location的值设为这个就可以了!
这个地址转换后应该是这样的: http://a.com/cookie.htm?.the9.com
由于ie的bug,误把前面那个的域名以为是.the9.com了!

hosts文件解释
hosts文件实际上可以看成一个本机的dns系统,它可以负责把域名解释成ip地址,它的优先
权比dns服务器要高,它的具体实现是TCP/IP协议中的一部分。
如果有这么一行:
202.109.110.3 www.the9.com
那么在输入www.the9.com时,网络协议会首先检查hosts文件找到匹配的,如果找不到再去d
ns查,这样你访问www.the9.com实际上是访问202.109.110.3,而不是通常的202.109.110.2

注:由于缓存的作用,如果开着浏览器编辑hosts的话,hosts里的内容有可能不会当场生效
,你可以重新启动浏览器或等一会时间再试一下!

关于REFERER的欺骗(这个虽然不属于cookie欺骗,但是懒得再写一篇,就归在一起
了)
referer是http头,它的作用是签定用户是从何处引用连接的,在the9,服务程序就充分利用
了这一点,如过你是手动输入url的话,那么referer不会设任何值,服务程序就返回什么“
投机取巧”的字样!
由于我们前面对浏览器进行了域名欺骗,那么referer也被欺骗了,但是服务程序对referer
是整个主机名检查,所以www0.the9.com的域名就欺骗不了服务器,所以得用www.the9.com欺
骗,那么还得设一个域名方便我们访问the9,而且还得让cookie返回给这个真的the9,那么
就用www0.the9.com吧!(这回知道前面访问我主页工具时要那样编辑hosts了吧?)
如果你用了这个方法的话,那么你就不能直接点击the9的连接,而得用工具中的地址欺骗来
进行访问,至于这样做的好处,大家自己找找吧,我就不想详细说了,太累了!

关于netvampire:
这个下载工具大家都知道吧?那么它的3.3版大家用过吗?很棒的!因为它可以直接让大家改
变下载连接的referer,而且它还能继承浏览器的cookie,把cookie返回给服务端(不过coo
kie不能改,如果能改的话,这个工具就太………………)

CGI编程的COOKIE技术应用

我们在一些留言本、BBS讨论区发贴时常会出现这种现象:当进入发贴界面时在要求填写用户名和密码的地方就已经自动地填上了你的资料。这是什么会事呢?这 是因为程序中引入了COOKIE技术的缘故。原来在你第一次登录时,程序就已在你的电脑中安装了一个COOKIE信息包,在你今后登陆时电脑就自动检索你 的COOKIE并取出信息包的信息供程序调用,所以出现上面所述的现象。
COOKIE只不过是CGI程序要求浏览器持有的一个信息包,这个信息包 可以由CGI程序在任何时候收回。每当CGI程序要求创建COOKIE时,COOKIE可以从服务器传送到浏览器所属的子目录下(通常是保存在C:\ WINDOWS\Temporary Internet Files的目录下,这个过程称为COOKIE的安装。
    COOKIE的安装和读出通常都由一个CGI模块来完成,下面我就将此模块的原代码公布给大家,有了这个COOKIE模块我们在编写程序时如要应用COOKIE技术可以说易如反掌。
cookie的语法:
http cookie的发送是通过http头部来实现的,他早于文件的传递,头部set-cookie的语法如下:
Set-cookie:name=name;expires=date;path=path;domain=domain;secure name=name: 需要设置cookie的值(name不能使用“;”和","号),有多个name值时用";"分隔例如:name1=name1;name2= name2;name3=name3。
expires=date: cookie的有效期限,格式: expires="Wdy,DD-Mon-YYYY HH:MM:SS"
path=path: 设置cookie支持的路径,如果path是一个路径,则cookie对这个目录下的所有文件及子目录生效,例如:path="/cgi-bin/",如 果path是一个文件,则cookie指对这个文件生效,例如:path="/cgi-bin/cookie.cgi"。
domain=domain: 对cookie生效的域名,例如:domain="gzdzw.51.net"
secure: 如果给出此标志,表示cookie只能通过SSL协议的https服务器来传递。
cookie的接收是通过设置环境变量HTTP_COOKIE来实现的,CGI程序可以通过检索该变量获取cookie信息。
以下是一个cookie的模块,可以为你编写程序带来方便
$Cookie_Exp_Date = '';#此处设置cookie的有效时间
$Cookie_Path = '';#此处设置cookie的有效路径,默认脚本存在的目录。
$Cookie_Domain = ''; #此处设置cookie的有效域名,默认脚本调用的域名。
$Secure_Cookie = '0';
@Cookie_Encode_Chars = ('\%', '\+', '\;', '\,', '\=', '\&', '\:\:', '\s');
%Cookie_Encode_Chars = ('\%', '%25',
'\+', '%2B',
'\;', '%3B',
'\,', '%2C',
'\=', '%3D',
'\&', '%26',
'\:\:', '%3A%3A',
'\s', '+');# 特殊字符的解码

@Cookie_Decode_Chars = ('\+', '\%3A\%3A', '\%26', '\%3D', '\%2C', '\%3B', '\%2B', '\%25');
%Cookie_Decode_Chars = ('\+', ' ',
'\%3A\%3A', '::',
'\%26', '&',
'\%3D', '=',
'\%2C', ',',
'\%3B', ';',
'\%2B', '+',
'\%25', '%');# 特殊字符的解码
#########获取cookie信息子程序#####################
sub GetCookies {
local(@ReturnCookies) = @_;
local($cookie_flag) = 0;
local($cookie,$value);
if ($ENV{'HTTP_COOKIE'}) {
if ($ReturnCookies[0] ne '') {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {#分割HTTP_COOKIE变量的字符串
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;#调用转码函数
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;#调用转码函数
}
foreach $ReturnCookie (@ReturnCookies) {
if ($ReturnCookie eq $cookie) {
$Cookies{$cookie} = $value;
$cookie_flag = "1";
}
}
}
}
else {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
$Cookies{$cookie} = $value;
}
$cookie_flag = 1;
}
}
return $cookie_flag;
}
########## 设置Cookie信息子程序#######################
sub SetSecureCookie {
if ($_[0] =~ /^[01]$/) {
$Secure_Cookie = $_[0];
return 1;
}
else {
return 0;
}
}
sub SetCookies {
local(@cookies) = @_;
local($cookie,$value,$char);
while( ($cookie,$value) = @cookies ) {
foreach $char (@Cookie_Encode_Chars) {
$cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g;#调用转码函数
$value =~ s/$char/$Cookie_Encode_Chars{$char}/g;#调用转码函数
}
print 'Set-Cookie: ' . $cookie . '=' . $value . ';';#设置cookie值
if ($Cookie_Exp_Date) { print ' expires=' . $Cookie_Exp_Date . ';'; }#设置有效时间
if ($Cookie_Path) { print ' path=' . $Cookie_Path . ';'; }#设置有效路径
if ($Cookie_Domain) { print ' domain=' . $Cookie_Domain . ';'; }#设置有效域名
if ($Secure_Cookie) { print ' secure'; }
print "\n";
shift(@cookies); shift(@cookies);
}
}
sub SetCompressedCookies {
local($cookie_name,@cookies) = @_;
local($cookie,$value,$cookie_value);
while ( ($cookie,$value) = @cookies ) {
foreach $char (@Cookie_Encode_Chars) {
$cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Encode_Chars{$char}/g;
}
if ($cookie_value) { $cookie_value .= '&' . $cookie . '::' . $value; }
else { $cookie_value = $cookie . '::' . $value; }
shift(@cookies); shift(@cookies);
}
&SetCookies("$cookie_name","$cookie_value");
}
sub GetCompressedCookies {
local($cookie_name,@ReturnCookies) = @_;
local($cookie_flag) = 0;
local($ReturnCookie,$cookie,$value);
if (&GetCookies($cookie_name)) {
if ($ReturnCookies[0] ne '') {
foreach (split(/&/,$Cookies{$cookie_name})) {
($cookie,$value) = split(/::/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
foreach $ReturnCookie (@ReturnCookies) {
if ($ReturnCookie eq $cookie) {
$Cookies{$cookie} = $value;
$cookie_flag = 1;
}
}
}
}
else {
foreach (split(/&/,$Cookies{$cookie_name})) {
($cookie,$value) = split(/::/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
$Cookies{$cookie} = $value;
}
$cookie_flag = 1;
}
delete($Cookies{$cookie_name});
}
return $cookie_flag;
}
########结束#################
下面是cookie信息包安装代码段
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE
expireDate = new Date;
if (expireDate.getYear() < 100) {
expireDate.setYear(expireDate.getYear() + 1900 + 1);
} else {
expireDate.setYear(expireDate.getYear()+1);
}
var username = getCookie("UserName");
var password = getCookie("Password");
if (password == null) {
var CookieName = "$username";
var CookiePW = "$userpsd";
if (password == null) {
document.cookie = "username=" + CookieName + ";expires=" + expireDate.toGMTString() + ";";
document.cookie = "password=" + CookiePW + ";expires=" + expireDate.toGMTString() + ";";
}
}
function getCookie(name){
var cname = name + "=";
var dc = document.cookie;
if (dc.length > 0) {
begin = dc.indexOf(cname);
if (begin != -1) {
begin += cname.length;
end = dc.indexOf(";", begin);
if (end == -1) end = dc.length;
return dc.substring(begin, end); }
}
return null;
}
// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>
###########结束#####################
下面是读取信息包代码,很简单:

&GetCookies;
$name=$Cookies{'username'};
$pass=$Cookies{'password'};

 

COOKIE的用途相信大家都知道了,有时我们的CGI需要记录读取某个来访者的信息,例如该来访者使用该CGI的情况,那就得用到COOIKE技术,下面就讨论一下如何用CGI来记录、读取来访者计算机中的COOKIE。

COOKIE在不同的浏览器上的存储方式是不同的,但这并不存在不兼容的问题,因为WEB服务器与浏览器之间是通过HTTP响应头实现互相传送COOKIE的信息的,我们在读写COOKIE时不必理会其在客户端是怎么存储的。

在CGI向来访者的计算机中写入一条COOKIE时,CGI需要向浏览器发送一个响应头:

Set-Cookie:name1=value;name2=value2;exprires=DATE;PATH=PATH;domiam=DOMAIN_NAME;SECURE

现在逐个来解释以上响应头各项的含义,各项内容是用分号阁开的

我们看到 name1=value和name2=value2 就是你要设置的COOKIE的内容,它是以名字=值的方式发送的,而name=value中不可以有冒号、逗号、和空格,但可以用%XX代替,XX为一个16进制数;

exprires=DATE项是有关COOKIES的生存期,即该COOKIE的有效期,有效期的时间格式是格林威治时间格式:wdy,DD-MON-YYYY HH:MM:SS GMT
这一项在写入COOIE时是可选的,但不设置的话浏览器与WEB服务器的一次连接结束后,COOKIE就过了有效期;

domian项定义哪些主机可以读取COOKIES,通常COOKIE存放的都不重要的信息,如果你要存放的的信息不大重要,这一项也不用设置;

PATH项是定义了一台主机上哪些WWW资源可以读取你所设置的COOKIE,如果PATH=/ 则这台主机上所有WWW资源可以读取你所设置的COOKIE;

SECURE是有关加密传送我们可不用理会。

如果你在一台支持COOKIE的客户端设置了COOKIE,当这个客户端在次来访问时,浏览器会向你的CGI所在的WEB服务器发送一条HTTP响应头,这个响应头为:
Cookie:name1=value;name2=value2;exprires=DATE;PATH=PATH;domiam=DOMAIN_NAME;SECURE
根据这个HTTP响应头WEB服务器的环境变量 HTTP_COOKIE=:name1=value;name2=value2
我们对这个环境变量的内容进行分解就可以的到我我们要的信息。

以下给出我写的读写COOKIE的两段PERL程序,你也可以把它改写为C语言

设置COOKIE:

print "Content-type:text/htmln";
print "Set-Cookie:name1=zjxyz;expires=Thursdday,01-Jan-2000 12:00:00 GMTn";
print "Set-Cookie:name2=ken;expires=Thursdday,01-Jan-2000 12:00:00 GMTn";
print "Set-Cookie:name3=ken;expires=Thursdday,01-Jan-2000 12:00:00 GMTnn";

读取COOKIE和分解的过程:

@pairs = split(/&/, $ENV{'HTTP_COOKIE'});
foreach $pair (@pairs){
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$cookie{$name} = $value;}

 

9.1 Cookie概述

Cookie是服务器发送给浏览器的体积很小的纯文本信息,用户以后访问同一个Web服务器时浏览器会把它们原样发送给服务器。通过让服务器读取它原先保 存到客户端的信息,网站能够为浏览者提供一系列的方便,例如在线交易过程中标识用户身份、安全要求不高的场合避免用户重复输入名字和密码、门户网站的主页 定制、有针对性地投放广告,等等。

Cookie的目的就是为用户带来方便,为网站带来增值。虽然有着许多误传,事实上Cookie并不会造成严重的安全威胁。Cookie永远不会以任何方 式执行,因此也不会带来病毒或攻击你的系统。另外,由于浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个 Cookie的大小限制为4 KB,因此Cookie不会塞满你的硬盘,更不会被用作“拒绝服务”攻击手段。

9.2 Servlet的Cookie API

要把Cookie发送到客户端,Servlet先要调用new Cookie(name,value)用合适的名字和值创建一个或多个Cookie(2.1节),通过cookie.setXXX设置各种属性(2.2 节),通过response.addCookie(cookie)把cookie加入应答头(2.3节)。

要从客户端读入Cookie,Servlet应该调用request.getCookies(),getCookies()方法返回一个Cookie对象 的数组。在大多数情况下,你只需要用循环访问该数组的各个元素寻找指定名字的Cookie,然后对该Cookie调用getValue方法取得与指定名字 关联的值,这部分内容将在2.4节讨论。

9.2.1 创建Cookie

调用Cookie对象的构造函数可以创建Cookie。Cookie对象的构造函数有两个字符串参数:Cookie名字和Cookie值。名字和值都不能包含空白字符以及下列字符:
[ ] ( ) = , " / ? @ : ;




9.2.2 读取和设置Cookie属性

把Cookie加入待发送的应答头之前,你可以查看或设置Cookie的各种属性。下面摘要介绍这些方法:

getComment/setComment
获取/设置Cookie的注释。
getDomain/setDomain
获 取/设置Cookie适用的域。一般地,Cookie只返回给与发送它的服务器名字完全相同的服务器。使用这里的方法可以指示浏览器把Cookie返回给 同一域内的其他服务器。注意域必须以点开始(例如.sitename.com),非国家类的域(如.com,.edu,.gov)必须包含两个点,国家类 的域(如.com.cn,.edu.uk)必须包含三个点。
getMaxAge/setMaxAge
获取/设置Cookie过期之前的时间,以秒计。如果不设置该值,则Cookie只在当前会话内有效,即在用户关闭浏览器之前有效,而且这些Cookie不会保存到磁盘上。参见下面有关LongLivedCookie的说明。
getName/setName
获取/设置Cookie的名字。本质上,名字和值是我们始终关心的两个部分。由于HttpServletRequest的getCookies方法返回的是一个Cookie对象的数组,因此通常要用循环来访问这个数组查找特定名字,然后用getValue检查它的值。
getPath/setPath
获取/设置Cookie适用的路径。如果不指定路径,Cookie将返回给当前页面所在目录及其子目录下的所有页面。这里的方法可以用来设定一些更一般的条件。例如,someCookie.setPath("/"),此时服务器上的所有页面都可以接收到该Cookie。
getSecure/setSecure
获取/设置一个boolean值,该值表示是否Cookie只能通过加密的连接(即SSL)发送。
getValue/setValue
获取/设置Cookie的值。如前所述,名字和值实际上是我们始终关心的两个方面。不过也有一些例外情况,比如把名字作为逻辑标记(也就是说,如果名字存在,则表示true)。
getVersion/setVersion
获取/设置Cookie所遵从的协议版本。默认版本0(遵从原先的Netscape规范);版本1遵从RFC 2109 , 但尚未得到广泛的支持。
9.2.3 在应答头中设置Cookie

Cookie可以通过HttpServletResponse的addCookie方法加入到Set-Cookie应答头。下面是一个例子:
Cookie userCookie = new Cookie("user", "uid1234");
response.addCookie(userCookie);




9.2.4 读取保存到客户端的Cookie

要把Cookie发送到客户端,先要创建Cookie,然后用addCookie发送一个Set-Cookie HTTP应答头。这些内容已经在上面的2.1节介绍。从客户端读取Cookie时调用的是HttpServletRequest的getCookies方 法。该方法返回一个与HTTP请求头中的内容对应的Cookie对象数组。得到这个数组之后,一般是用循环访问其中的各个元素,调用getName检查各 个Cookie的名字,直至找到目标Cookie。然后对这个目标Cookie调用getValue,根据获得的结果进行其他处理。

上述处理过程经常会遇到,为方便计下面我们提供一个getCookieValue方法。只要给出Cookie对象数组、Cookie名字和默认值, getCookieValue方法就会返回匹配指定名字的Cookie值,如果找不到指定Cookie,则返回默认值。

9.3 几个Cookie工具函数

下面是几个工具函数。这些函数虽然简单,但是,在和Cookie打交道的时候很有用。

9.3.1 获取指定名字的Cookie值

该函数是ServletUtilities.java的一部分。getCookieValue通过循环依次访问Cookie对象数组的各个元素,寻找是否 有指定名字的Cookie,如找到,则返回该Cookie的值;否则,返回参数中给出的默认值。getCookieValue能够在一定程度上简化 Cookie值的提取。
public static String getCookieValue(Cookie[] cookies,
String cookieName,
String defaultValue) {
for(int i=0; i<cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName()))
return(cookie.getValue());
}
return(defaultValue);
}




9.3.2自动保存的Cookie

下面是LongLivedCookie类的代码。如果你希望Cookie能够在浏览器退出的时候自动保存下来,则可以用这个LongLivedCookie类来取代标准的Cookie类。
package hall;

import javax.servlet.http.*;

public class LongLivedCookie extends Cookie {
public static final int SECONDS_PER_YEAR = 60*60*24*365;
public LongLivedCookie(String name, String value) {
super(name, value);
setMaxAge(SECONDS_PER_YEAR);
}
}




9.4.实例:定制的搜索引擎界面

下面也是一个搜索引擎界面的例子,通过修改前面HTTP状态代码的例子得到。在这个Servlet中,用户界面是动态生成而不是由静态HTML文件提供 的。Servlet除了负责读取表单数据并把它们发送给搜索引擎之外,还要把包含表单数据的Cookie发送给客户端。以后客户再次访问同一表单时,这些 Cookie的值将用来预先填充表单,使表单自动显示最近使用过的数据。

SearchEnginesFrontEnd.java

该Servlet构造一个主要由表单构成的用户界面。第一次显示的时候,它和前面用静态HTML页面提供的界面差不多。然而,用户选择的值将被保存到 Cookie(本页面将数据发送到CustomizedSearchEngines Servlet,由后者设置Cookie)。用户以后再访问同一页面时,即使浏览器是退出之后再启动,表单中也会自动填好上一次搜索所填写的内容。

注意该Servlet用到了ServletUtilities.java,其中getCookieValue前面已经介绍过,headWithTitle 用于生成HTML页面的一部分。另外,这里也用到了前面已经说明的LongLiveCookie类,我们用它来创建作废期限很长的Cookie。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;

public class SearchEnginesFrontEnd extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
String searchString =
ServletUtilities.getCookieValue(cookies,
"searchString",
"Java Programming");
String numResults =
ServletUtilities.getCookieValue(cookies,
"numResults",
"10");
String searchEngine =
ServletUtilities.getCookieValue(cookies,
"searchEngine",
"google");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Searching the Web";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H1 ALIGN=\"CENTER\">Searching the Web</H1>\n" +
"\n" +
"<FORM ACTION=\"/servlet/hall.CustomizedSearchEngines\">\n" +
"<CENTER>\n" +
"Search String:\n" +
"<INPUT TYPE=\"TEXT\" NAME=\"searchString\"\n" +
" VALUE=\"" + searchString + "\"><BR>\n" +
"Results to Show Per Page:\n" +
"<INPUT TYPE=\"TEXT\" NAME=\"numResults\"\n" +
" VALUE=" + numResults + " SIZE=3><BR>\n" +
"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
" VALUE=\"google\"" +
checked("google", searchEngine) + ">\n" +
"Google |\n" +
"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
" VALUE=\"infoseek\"" +
checked("infoseek", searchEngine) + ">\n" +
"Infoseek |\n" +
"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
" VALUE=\"lycos\"" +
checked("lycos", searchEngine) + ">\n" +
"Lycos |\n" +
"<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +
" VALUE=\"hotbot\"" +
checked("hotbot", searchEngine) + ">\n" +
"HotBot\n" +
"<BR>\n" +
"<INPUT TYPE=\"SUBMIT\" VALUE=\"Search\">\n" +
"</CENTER>\n" +
"</FORM>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n");
}

private String checked(String name1, String name2) {
if (name1.equals(name2))
return(" CHECKED");
else
return("");
}
}




CustomizedSearchEngines.java

前面的SearchEnginesFrontEnd Servlet把数据发送到CustomizedSearchEngines Servlet。本例在许多方面与前面介绍HTTP状态代码时的例子相似,区别在于,本例除了要构造一个针对搜索引擎的URL并向用户发送一个重定向应答 之外,还要发送保存用户数据的Cookies。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;

public class CustomizedSearchEngines extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

String searchString = request.getParameter("searchString");
Cookie searchStringCookie =
new LongLivedCookie("searchString", searchString);
response.addCookie(searchStringCookie);
searchString = URLEncoder.encode(searchString);
String numResults = request.getParameter("numResults");
Cookie numResultsCookie =
new LongLivedCookie("numResults", numResults);
response.addCookie(numResultsCookie);
String searchEngine = request.getParameter("searchEngine");
Cookie searchEngineCookie =
new LongLivedCookie("searchEngine", searchEngine);
response.addCookie(searchEngineCookie);
SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();
for(int i=0; i<commonSpecs.length; i++) {
SearchSpec searchSpec = commonSpecs[i];
if (searchSpec.getName().equals(searchEngine)) {
String url =
searchSpec.makeURL(searchString, numResults);
response.sendRedirect(url);
return;
}
}
response.sendError(response.SC_NOT_FOUND,
"No recognized search engine specified.");
}

public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics