Web层主要功能是处理http协议,处理web服务器业务。可以说是整个web服务器的重点。
对于其的详细分析,以后再写。
一个基本认证例子的消息头:
请求。
POST /goform/cfgSdhifRsWeb HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://192.168.4.28/sdhifrs.asp?slot=0
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.4.28
Content-Length: 137
Proxy-Connection: Keep-Alive
Pragma: no-cache
Authorization: Basic cmFpc2Vjb206cmFpc2Vjb20=
portIndex=1&exc=3&sd=6&es=900&ses=900&msais_insert=2&j0_mode=2&j0_transmit=Raisecom-Opcom+&j0_expected=Raisecom-Opcom+&slot=0&apply=Apply
响应。
HTTP/1.0 302 Redirect
Server: Webs/2.5.0
Date: THU JAN 01 00:06:48 1970
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html
Location: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1
<html><head></head><body>
This document has moved to a new <a href="http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1">location</a>.
Please update your documents to reflect the new location.
</body></html>
一个摘要认证例子的消息头:
请求。
POST /goform/cfgSdhifRsWeb HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.4.28
Content-Length: 137
Proxy-Connection: Keep-Alive
Pragma: no-cache
Authorization: Digest username="123",realm="123",nonce="0fabdfd5b279fadc2f0d9d72ed218c29",uri="/goform/cfgSdhifRsWeb",cnonce="e5003c43b0ba085d63cd1e92021c6ecc",nc=00000019,algorithm=MD5,response="a97274a2c9d6e8ccbb7e9200c1bc4e56",qop="auth",opaque="5ccc069c403ebaf9f0171e9517f40e41"
portIndex=1&exc=3&sd=6&es=900&ses=900&msais_insert=2&j0_mode=2&j0_transmit=Raisecom-Opcom+&j0_expected=Raisecom-Opcom+&slot=0&apply=Apply
响应。
HTTP/1.0 302 Redirect
Server: Webs/2.5.0
Date: THU JAN 01 00:01:54 1970
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html
Location: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1
<html><head></head><body>
This document has moved to a new <a href="http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1">location</a>.
Please update your documents to reflect the new location.
</body></html>
HTTP Keep-Alive
Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。市场上 的大部分Web服务器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,这里存在另外一个问题:虽然为客户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep- Alive功能对资源利用的影响尤其突出。 此功能为HTTP 1.1预设的功能,HTTP 1.0加上Keep-Alive header也可以提供HTTP的持续作用功能。
Keep-Alive: timeout=5, max=100
timeout:过期时间5秒(对应httpd.conf里的参数是:KeepAliveTimeout),max是最多一百次请求,强制断掉连接
就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。
If-Modified-Since
If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。
如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。
如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
HTTP的If-Modified-Since头标签与客户端缓存相互配合,大大节约了网络流量。
HTTP的认证模式
Http协议(RFC 2616 )规定可以采用Base模式和摘要模式(Digest schema)。RFC 2617 专门对两种认证模式做了规定。RFC 1321 是MD5标准。Digest对现代密码破解来说并不强壮,但比基本模式还是好很多。MD5已经被山东大学教授找到方法可以仿冒(我的理解),但现在还在广泛使用。
1.最简单的攻击方式
如果网站要求认证,客户端发送明文的用户名密码,那网络上的窃听者可以轻而易举的获得用户名密码,起不到安全作用。我上学时曾在科大实验室局域网内窃听别人的科大BBS的密码,发现BBS的用户名密码居然是明文传输的。那种做贼的心虚和做贼的兴奋让人激动莫名。偷人钱财会受到道德谴责,偷人密码只会暗自得意忘形。比“窃书不算偷”还没有罪恶感。因此你的用户名和密码明文传输的话,无异将一块肥肉放在嘴馋的人面前。现在很多ASP网站的认证都将用户名和密码用MD5加密。MD5是将任意长度的字符串和128位的随机数字运算后生成一个16byte的加密字符串。因此窃听者抓住的是一团乱码。但是,这有一个问题:如果窃听者就用这团乱码去认证,还是可以认证通过。因为服务器将用户名密码MD5加密后得到的字符串就是那一团乱码,自然不能区别谁是合法用户。这叫重放攻击(replay attack)。这和HTTP的基本认证模式差不多。为了安全,不要让别人不劳而获,自然要做基本的防范。下面是Http协议规定的两种认证模式。
2.基本认证模式
客户向服务器发送请求,服务器返回401(未授权),要求认证。401消息的头里面带了挑战信息。realm用以区分要不同认证的部分。客户端收到401后,将用户名密码和挑战信息用BASE64加密形成证书,发送回服务器认证。语法如下:
challenge = "Basic" realm
credentials = "Basic" basic-credentials
示例:
认证头: WWW-Authenticate: Basic realm="[email protected]"
证书:Authorization: Basic QsdfgWGHffuIcaNlc2FtZQ==
3.摘要访问认证
为了防止重放攻击,采用摘要访问认证。在客户发送请求后,收到一个401(未授权)消息,包含一个Challenge。消息里面有一个唯一的字符串:nonce,每次请求都不一样。客户将用户名密码和401消息返回的挑战一起加密后传给服务器。这样即使有窃听,他也无法通过每次认证,不能重放攻击。Http并不是一个安全的协议。其内容都是明文传输。因此不要指望Http有多安全。
语法:
challenge = "Digest" digest-challenge
digest-challenge = 1#( realm | [ domain ] | nonce |
[ opaque ] |[ stale ] | [ algorithm ] |
[ qop-options ] | [auth-param] )
domain = "domain" "=" <"> URI ( 1*SP URI ) <">
URI = absoluteURI | abs_path
nonce = "nonce" "=" nonce-value
nonce-value = quoted-string
opaque = "opaque" "=" quoted-string
stale = "stale" "=" ( "true" | "false" )
algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
token )
qop-options = "qop" "=" <"> 1#qop-value <">
qop-value = "auth" | "auth-int" | token
realm:让客户知道使用哪个用户名和密码的字符串。不同的领域可能密码不一样。至少告诉用户是什么主机做认证,他可能会提示用哪个用户名登录,类似一个Email。
domain:一个URI列表,指示要保护的域。可能是一个列表。提示用户这些URI采用一样的认证。如果为空或忽略则为整个服务器。
nonce:随机字符串,每次401都不一样。跟算法有关。算法类似Base64加密:time-stamp H(time-stamp ":" ETag ":" private-key) 。time-stamp为服务器时钟,ETag为请求的Etag头。private-key为服务器知道的一个值。
opaque:服务器产生的由客户下去请求时原样返回。最好是Base64串或十六进制字符串。
auth-param:为扩展用的,现阶段忽略。
其他域请参考RFC2617。
授权头语法:
credentials = "Digest" digest-response
digest-response = 1#( username | realm | nonce | digest-uri
| response | [ algorithm ] | [cnonce] |
[opaque] | [message-qop] |
[nonce-count] | [auth-param] )
username = "username" "=" username-value
username-value = quoted-string
digest-uri = "uri" "=" digest-uri-value
digest-uri-value = request-uri ; As specified by HTTP/1.1
message-qop = "qop" "=" qop-value
cnonce = "cnonce" "=" cnonce-value
cnonce-value = nonce-value
nonce-count = "nc" "=" nc-value
nc-value = 8LHEX
response = "response" "=" request-digest
request-digest = <"> 32LHEX <">
LHEX = "0" | "1" | "2" | "3" |
"4" | "5" | "6" | "7" |
"8" | "9" | "a" | "b" |
"c" | "d" | "e" | "f"
response:加密后的密码
digest-uri:拷贝Request-Line,用于Proxy
cnonce:如果qop设置,才设置,用于双向认证,防止攻击。
nonce-count:如果服务器看到同样的计数,就是一次重放。
示例:
401响应: HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest
realm="[email protected]",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
再次请求:
Authorization: Digest username="Mufasa",
realm="[email protected]",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="/dir/index.html",
qop=auth,
nc=00000001,
cnonce="0a4f113b",
response="6629fae49393a05397450978507c4ef1",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
4.比较基本认证和摘要访问认证都是很脆弱的。基本认证可以让窃听者直接获得用户名和密码,而摘要访问认证窃听者只能获得一次请求的文档。
int websOpenServer(int port, int retries)
功能:打开web服务器,打开rom,创建mime table,打开url处理模块打开form 模块,打开监听socket
说明:
-----------------------------------------------------------------------------------------------------------------
void websCloseServer()
功能:关闭web服务器,关闭监听socket,关闭已经连接的socket
说明:
-----------------------------------------------------------------------------------------------------------------
int websOpenListen(int port, int retries)
功能:打开监听socket
说明:
-----------------------------------------------------------------------------------------------------------------
void websCloseListen()
功能:关闭监听socket
说明:
-----------------------------------------------------------------------------------------------------------------
int websAccept(int sid, char *ipaddr, int port, int listenSid)
功能:接收一个连接,创建钩子函数websSocketEvent,对应于该socket可读,设置该socket挂起请求的超时处理函数websTimeout
说明:
-----------------------------------------------------------------------------------------------------------------
static void websSocketEvent(int sid, int mask, void* iwp)
功能:响应读写操作
说明:
-----------------------------------------------------------------------------------------------------------------
void websReadEvent(webs_t wp)
功能:读操作响应函数,是web服务器读取从浏览器发来的数据,读取数据是分阶段的,WEBS_BEGIN、WEBS_HEADER、WEBS_POST_CLEN、WEBS_POST
说明:
-----------------------------------------------------------------------------------------------------------------
static int websGetInput(webs_t wp, char_t **ptext, int *pnbytes)
功能:从浏览器获取数据
说明:
-----------------------------------------------------------------------------------------------------------------
static int websParseFirst(webs_t wp, char_t *text)
功能:分析http请求的第一行
说明:
-----------------------------------------------------------------------------------------------------------------
static void websParseRequest(webs_t wp)
功能:分析head全部请求
说明:
-----------------------------------------------------------------------------------------------------------------
void websSetEnv(webs_t wp)
功能:设置环境变量
说明:
-----------------------------------------------------------------------------------------------------------------
void websSetVar(webs_t wp, char_t *var, char_t *value)
功能:设置web变量
说明:
-----------------------------------------------------------------------------------------------------------------
int websTestVar(webs_t wp, char_t *var)
功能:测试这个cgi 变量是否存在
说明:
-----------------------------------------------------------------------------------------------------------------
char_t *websGetVar(webs_t wp, char_t *var, char_t *defaultGetValue)
功能:获取web的变量,主要是post的表单数据或query数据
说明:
-----------------------------------------------------------------------------------------------------------------
int websCompareVar(webs_t wp, char_t *var, char_t *value)
功能:是否这个web变量
说明:
-----------------------------------------------------------------------------------------------------------------
void websTimeoutCancel(webs_t wp)
功能:超时处理取消函数
说明:
-----------------------------------------------------------------------------------------------------------------
void websResponse(webs_t wp, int code, char_t *message, char_t *redirect)
功能:向浏览器输出web服务器的响应
说明:
-----------------------------------------------------------------------------------------------------------------
void websRedirect(webs_t wp, char_t *url)
功能:web重定向,定位到另一个页面
说明:
-----------------------------------------------------------------------------------------------------------------
static int charCount(const char_t* str, char_t ch)
功能:统计字符ch在字符串str中出现的次数
说明:
-----------------------------------------------------------------------------------------------------------------
static char_t* websSafeUrl(const char_t* url)
功能:主要是将<、>字符转换为<、>
说明:
-----------------------------------------------------------------------------------------------------------------
void websError(webs_t wp, int code, char_t *fmt, ...)
功能:向浏览器输出错误
说明:
-----------------------------------------------------------------------------------------------------------------
char_t *websErrorMsg(int code)
功能:根据错误码输出对应的解释性字符
说明:
-----------------------------------------------------------------------------------------------------------------
int websWrite(webs_t wp, char_t *fmt, ...)
功能:向浏览器输出字符串
说明:
-----------------------------------------------------------------------------------------------------------------
int websWriteBlock(webs_t wp, char_t *buf, int nChars)
功能:向浏览器一段数据
说明:
-----------------------------------------------------------------------------------------------------------------
int websWriteDataNonBlock(webs_t wp, char *buf, int nChars)
功能:向浏览器一段数据
说明:
-----------------------------------------------------------------------------------------------------------------
void websDecodeUrl(char_t *decoded, char_t *token, int len)
功能:url解码函数,主要是将+、%xx等解码成空格、字符
说明:
-----------------------------------------------------------------------------------------------------------------
void websTimeout(void *arg, int id)
功能:超时处理函数,如果超时,则释放内存,向浏览器输出结果,如果还未超时,重新启动定时函数,定时的时间为剩余的时间
说明:
-----------------------------------------------------------------------------------------------------------------
void websDone(webs_t wp, int code)
功能:一个请求处理完成的结束函数,向浏览器输出数据,释放内存
说明:
-----------------------------------------------------------------------------------------------------------------
int websAlloc(int sid)
功能:分配一个webs_t结构
说明:
-----------------------------------------------------------------------------------------------------------------
void websFree(webs_t wp)
功能:?