浅谈B/S系统安全

类别:编程语言 点击:0 评论:0 推荐:

这是发表在原公司(已经在股东们个人利益斗争中轰然倒塌)内部BBS上的一篇贴子,随便贴上来,(为保护在用系统及其它有部分删节及修改),适合初学者!

[email protected]

http://www.safechina.net (转载请注明出处)

-----------------------------------------------------------
浅谈B/S系统安全
    随着这些年的发展B/S系统已经超出了个人主页,留言本之类的应用,各种公司的核心应用都逐渐构建在WEB上了,而WEB服务器端的程序安全也倍受瞩目,本文先通过几个实例引入一些常见的安全问题,然后讨论一下WEB应用代码编写的一些基本准则和建议。由于本人已很长时间不从事这方面的工作了,所讲的内容可能有些过时或不对的地方,各位看官就权当笑话。

如果不想看冗长无味的论述,就直接翻到:“一些编程原则”部分。

一. SQL注入(SQL Injection)
    这是现在出现的最多也最易应用的一个问题,使用数据库的系统就有可能出现这种问题,成因是对用户的输入没有做必要的检测及过滤,导致用户执行非法SQL语句。常见的如登陆程序,使用1’or ‘1’=’1进行任意用户登陆,记得98年台湾李登X的网站就是因此被黑….呵呵,好些年了,不过问题依然。 对于这类问题的网上已经有无数的实例和教学,本来不想趟这混水,不过正是由于其普遍性(我见过至少5个厂商10个以上的电信行业中的各种web系统存在不同程度上的登陆问题)和埋在其深处的语义方面的内容,所以决定从2003年底某系统的代码分析记录谈起。
例一:
以下内容来自2003年底的代码分析记录,代码文件的最后修改日期为2003.12.XX
XX帐务--XX管理系统
等级:AAA 严重

情景:登陆
条件 已经某合法用户名(非必要条件),如:tt。
过程:登陆界面中输入
操作员:1’or ‘1’=’1
口令:随便
执行结果:登陆成功,拥有所有操作权限。
问题分析
login_check.jsp
line 15处开始:
    此处没进行用户输入有效性处理………
    user_code = request.getParameter("user_code").trim();    
    strSql = "select count(*) from UserInfo where user_code = ‘"+ user_code +"‘ and password = ‘" +password+ "‘ and status=1";

以上查询为问题出处,当user_code为tt’ or 1=1 时strSql 为:
where user_code=’tt’ OR 1=1 and password=’aaa’ and status=1
结果为表中所有记录…..,通过对user_code输入值的构造几乎可以对数据库进行任何操作,部分数据库系统中可能获取系统最高权限……….
上面描述的是SQL Injection问题,进一步的转为应用逻辑完整性判断的讨论,用户登陆需要强壮的判断逻辑,仅判断是否返回结果是不够的,还应该加上查询结果的字段的内容是否与对应的输入一致,这样即使查询结果返回多条记录也不会登陆成功,上例中执行完述查询后因为不严谨的判断,不但导致用户登陆成功,而且还拥有系统的所有操作权限:    

    if (count.equals("0")){
            登陆失败,错误处理。
        }else{
            strSql = "select 字段名 from UserInfo where user_code = ‘"+ user_code +"‘";
以上语句由于user_code中有一or条件,所以取得系统的所有操作权限…….
设置session查询模块权限...

            if(userInfo != null){
                    此处成功进入系统。Redirect………
            }
    SQL Injection,最出名的可能就是动网的BBS系统(dvbbs)了,引起问题的主要原因是没对用户输入的合法性进行检查(这几乎是B/S系统中所有的问题的关键)[其实动网是一个很不错的程序,如果当初不是选择asp来做的话,相信这类问题会少很多也可能获得更大的成功。]
解决方法:过虑用户输入,对查询结果进行有效性判断。如果上文中不是简单的用if (count.equals("0"))来进行验证而是判断两个password是否一致时,那系统外部人员就比较困难登陆了(但仍可执行非法语句),而系统内部有某个合法帐号的人仍可登陆有任意用户(很大一部分攻击来自于机构内部)。较好的方法:
1.过虑输入,如:限制用户名、密码只能为[a-zA-Z0-9]并限定长度,过虑[‘][“]之类的特殊符号 (严格的输入控制)
2.验证数据库中查询的结果、用户名的输入一致(强壮的应用逻辑}
3.如果你使用的语言可以使用类似parameters(….)来设置参数,就不要用字符串+来操作数据库操作语句,这样不仅使你的代码更有效率(如String对象的构造、oracle对sql的解析等),也使你的代码更安全。 (良好的编程风格)
网络录音机:

一.WEB安全就是SQL Injection!

二.入侵不难,会SQL就行…..

    但是SQL Injection不是全部,入侵真那么简单吗?比起前些年也许是的,因为那时的我无论跑到哪里的新华书城都找不到现在地摊上都有得卖的《黑客大全》


二.无效的数据权限验证
一般系统的权限模块都分为功能权限和数据权限:
功能权限:指操作者能使用的软件功能模块。
数据权限:指操作者能操作的数据。
仅控制操作权限却没有良好的控制数据权限可能导致越权操作,造成严重的后果。
例二: 代码及说明略。

比如:用户有权限编辑自己的资料及修改个人密码(修改资料的功能权限),如:访问edit.php?user_name=leo进行操作,但是如果程序没有完整的考虑数据权限(不能修改其他人的资料),导致越权操作,如:入侵者修改传入edit.php的user_name参数便可修改他人的资料(edit.php?user_name=admin)
    以上只是独立环境下一个简单的说明示例,在复杂系统中由于人员权限等级划分及管理模式的复杂性、不确定性加之开发人员理解上的差异,以及模块间的交互,开发和测试人员往往不能穷尽所有可能性,导致这类问题非常普遍。如果说系统登陆界面是系统的第一道门,它决定什么应该放在门里,什么应该放在门外的话,那么系统权限控制就是决定在屋子里的人们什么能做和什么不能做,这就像我们的行为规范,你应该知道红灯停,绿灯行,但是总是有那些不守规则的人,会去违反这些准则,导致我们开车时即使看到绿灯也要小心的防范着不会有人突然冲出来,甚至管理部门需要在路口设置监控器和协管员,以控制那些不守规则的人,权限管理就像是这些行为规划和协管员,以一种强制的手段,决定你应该做什么和不能做什么,如果权限管理出了问题,就你是一个非常繁忙的十字路口没有红绿灯一样à混乱。呵呵,扯远了,其实系统权限模型是一个很复杂的主题,从我的第一个应用起,好些系统,好些年了我也没能搞出个像样的来,不敢枉自评论些什么,期待高人指点。www.jdon.com有几篇不错的讨论,大家可以去看看(虽然我非常讨厌那个站长)。
网络录音机:

一.网络是自由的,网络是共享的!

二.什么忘记密码了?用admin登陆吧,我把他的密码改成1234了,方便记忆嘛!

但是你是否愿意共享昨天晚上你MM刚拍的写真呢?呵呵…..

 

三.访问源文件或其它重要资源…

体验了DBMS的强大,经历了森严的等级社会,让我们回到古老却又是万物根基的à文件系统。

有人要说:既然数据库不安全那我用文件算了,这个我熟….   

是真的吗?
    入侵的最终目的是什么?(嗯,或许对于某些人不是目的而是途径),是信息(这不是废话嘛),文件即是信息,信息就是文件(当然文件只是信息的一种组织方式,我们不讨论那么高深的辨证问题,^_^),当一个外部的creaker想要取得什么权限的时候,最想得到的信息是什么,密码!是的,当然如果有得选择的话我会选择取得目标文件,暴破密码太累了(況且对于一般人来说取得密码只是达到目的的途径)。这里所指的的文件可能XX公司的机密文件也可能是jsp、php,或asp源码,或都是/etc/passwd之类的东西。这并不容易,但绝非不可能(虽然不敢说impossible is nothing)……
 

以下内容为2003.06对国内某站点的安全分析记录,由于种种原因,请不要在公网发布以下内容,谢谢:
   另:种种原因发贴前我还是决定把段删了…  呵呵,篇幅太长了… ^_^

有目录为/usr/local/share/bin,我们很清楚cd /usr/local/share/bin是什么意思,但是

cd /usr/local/share/../../../bin是什么意思或许你就不是很清楚了?执行的结果是/bin(windows下一样成立),真不明白?回去好好看看相对路径绝对路径的定义….

 

如:一个页面根据参数读取指定文件并将文件内容显示给客户端,如果读文件的时候没限制可访问的文件,导致程序通过相对路径访问系统所有文件,从而泄露入侵者感兴趣的所有文件,如系统源代码。    不知各位还记不记得 (2000年?)绿色兵团yuange发现的IIS的unicode其实也是利用../../../来访问系统文件的(..%255c..%255c..winnt/system32/cmd.exe)。

    这种问题很普遍,前些天帮一个朋友看他的web server源代码(C语言)就发现了这个问题(将在另一篇文章中讲到,此君的技术水平,我只能用来瞻仰),解决方法可以也比较多,我觉的较好的是:
unix中使用realpath(3)
char *realpath(const char *path, char *resolved_path);
windows中使用
DWORD GetFullPathName(LPCTSTR lpFileName, DWORD nBufferLength, LPTSTR lpBuffer,LPTSTR *lpFilePath);
取得所传入参数的真实路径名,与系统允许的路径(或文件列表)相比较,确定是否可以访问此目录(文件)。Php的c源代码中的access_control部分也有比较不错的解决方法 (http://www.php.net), 我不大清楚java有没相应的库,如果没有,可以用JNI来调用上述两个函数来实现。


一些编程原则:

培养编码人员及测试人员的安全意识和良好编程习惯,现在B/S系统的成功与否,系统安全性起着重要的作用,管理人员也应该逐渐重视系统安全的问题。对于输入输出的检测及能否写出安全的代码是检验一个WEB程序是否合格的重要标准。

 

一.对用户的输入进行合法性校验,在必要的时候对输入数据中的[‘][“]字符进行转意,使用强制类型语言时应将输入转为相应类型。当然有些人对于所有输入做一样的控制,比如说将所有的单引号变成两个单引号,也是不合理的(如:输入保存后再取出来时与原始输入不一致),应该尽量清楚的了解系统的数据流,根据具体情况进行控制。一般有两种输入、输出控制,宽进严出和严进宽出,各有特点,也各有适用情况,对输入的控制能够解决大部份的代码安全问题,第一个例子中所讲述的SQL语句的问题如果做了较好的输入控制作再加上合理的判断逻辑,可以得到很好的解决。

二.不仅检查用户输出的数据,还要防范非用户直接输出的数据,如Cookies、环境变量等,不要用cookie到保存核心应用数据,因为http包很容易构造,当使用post方式不影响系统使用时(如后退),就尽量避免使用get方式(非常基本方式,我们发现这条非常有用,至少对于一些小黑来说,如果不是很方便的进行测试,便没多少耐心再做下去了,有时候我也这样)。 时刻记着:不是所有用户都是按着你的构建好的路径去操作系统的
    对模块间的数据流应当进行必要的检查和安全防范措施。作为一个对系统安全有重要影响的人你做到这一点了吗?你轻信你同伴们写的代码,或发送过来的数据吗?你确保这些数据在你的程序接收到之前没被人修改过吗??
    当你用一个手指指向别人时,还有三个手指指向你自己。---一个间谍 !(现在我已经忘记当初为什么引用这么一句话,但是我想从一种另一种负责的角度来看在工作及学习中持有一种怀疑的态度绝对是好事。2004-11-11)

三.在服务器上部署完后,把文件和目录权限设置为任何人都只能读,并将配置目录(需要经常修改的目录)设为不可执行,这样一般情况下别人就不能改你主页和代码了,也不能放木马上去了,script木马是非常可怕的。不但杀毒软件找不到,管理员也不容易找到,如果它嵌入你的代码时(修改你的代码,加某个条件才执行),那就更可怕了。
只读权限还可以防止开发、维护人员误删除在用系统的程序和配置,hehe,想到这事,我手心就开始冒汗,真是惊心动魄哪,记得有人说:没误删过数据,不谈流程。不过我想还是别拿在用系统不当回事。

四.不要图一时快捷把input、textarea、hidden之类的控件名称设置为数据库中的字段名,这样人们就很容易掌握数据库的命名规则,对于入侵者来说这是一大的信息来源。只要他掌握的信息足够多了你也就完了。我觉得这方面vs.net画出来的web form做得不错,近乎乱码.  -:)你根本不知道这个变量是做什么的。

五.不要发布Debug版本的程序,而发布Release版本的,发布系统时将所有的业务无关的信息输出关闭,封锁所有的系统错误信息(为方便查错可写后台日志)。成功入侵往往从出错开始信息开始。

 

六.不要直接拿变量来组成SQL语句!!!!!!!!!!!!!见例一描述。

 

七.输入、输入、输入,再怎么强调检测输入都是不过分的。至少应该进行一些基本的有效性判断,我觉得用java开发的应用从struts的validate,到AOP来进行权限控制,都有很好的解决方案.

 

八.以下建议来自《Secure Programming Cookbook for C and C++》Chapter 3. Input Validation,虽然这本书讲的是编写安全的C/C++代码,但是这几个原则对于任何程序都一样有效:
3.1.2 Solution
Perform data validation at all levels whenever possible. At the very least, make sure data is filtered on input.
Match constructs that are known to be valid and harmless. Reject anything else.
    In addition, be sure to be skeptical about any data coming from a potentially insecure channel. In a client-server architecture, for example, even if you wrote the client, the server should never assume it is talking to a trusted client.
1.    Assume all input is guilty until proven otherwise.
2.    Prefer rejecting data to filtering data.
3.    Perform data validation both at input points and at the component level.
4.    Do not accept commands from the user unless you parse them yourself.
5.    Beware of special commands, characters, and quoting.
6.    Make policy decisions based on a "default deny" rule.
7.    You can look for a quoting mechanism, but know how to use it properly.
8.    When designing your own quoting mechanisms, do not allow escapes.
9.    The better you understand the data, the better you can filter it. 这一句绝对经典,要知己知彼,试着以入侵者的角度考虑你的系统安全(本文最后部分将进行相关讨论)。


本文仅讨论了Web程序的安全,而系统的安全是这一切的基础,系统安全都不能保证的情况下,谈论程序安全就没有任何意义了,不过这是系统管理员的事情了^_^,但编写健壮安全的代码绝对是一名合格的程序员的基本职责。

此处删去五百一十六字……(不是限制级内容,呵呵)

 

以下内容来自己于另一文章,有些想法很幼稚,实在不敢show出来,取部分内容大家一起讨论

       记得从我刚开始进入网络世界时,就不断有人告诉我入侵需要耐力和运气(最初应该是coolfire的教程,不知还有没人记得),很多时候是这样子的,但是近来我越来越觉了要成功的找到一个漏洞并加以利用,拥有高超的技术,先进的工具,完整的列表,耐心和敏锐的嗅觉往往是不够的,我们还需要知道开发人员在写代码时以及系统管理员进行安全策略设置时的心理,是的“心理学”,虽然中学的时候我沉迷心理学,并有志于成为一名“伟大的”律师,但是这种各种心理学分支往往强调的是事物的唯一解,在查找漏洞的时候基本用不上,我们要高效的找到问题所在,需要的或许是“程序开发心理学”或是“安全策略心理学”之类的东西。

安全问题是由程序的问题引起的,程序反映程序开发者(人类)的心智,但是由于人类天生就是不完美的,所以他们所创造的事物也总是有缺陷的,而人与人之间总有着很多相似的方面,所以代码的错误也存在普遍性(我想没谁敢说从他写第一行代码开始就没犯过off by 1的错误),所以程序查错和漏洞检测总是存在一定普遍规律,这需要经验、灵感更需要了解开发者的心理(没写过代码的人基本不会知道埋藏在程序出错的表面现象下的是什么?),但是遗憾的是我们的高手们往往关注的只是入侵的手段及过程的记录,却忽略了在无尽的尝试中与程序作者的心灵上的交流(除了很久以前的《密码心理学》之外几乎没看见过其它从心理角度谈论程序漏洞的文章,而严格意义上讲《密码心理学》也不属于这个范围),其实很多情况下只要你了解程序作者的心理,那么问题将不再是问题了,否则也许真的只能靠运气和耐力了。

有一个经历让我更加深刻的认识到了解程序开发者当时的心理是多很的重要:至少在半年前,我发现国内某知名的网络安全站点的WEB程序存在问题,但是几乎用尽我所有的耐心试了所有可能的方法都不能成功的利用这个问题(但至今我仍坚信这个漏洞可以利用),也许真是我的运气不好,不过程序的怪异表现实在使我无法猜透程序完整错误逻辑在哪(或者说作者当时的想法,当然有可能作者是非常高的高人,他的思想不是我辈所能猜到的)。所以我迫切希望哪天能看到有人写出(或整理出)程序漏洞心理学,说明由于人类思想的哪些缺陷而导致的普遍程序问题。

呵呵,见笑了!



Hehe,好累,本人文采很差,很多东西想到了也写不出来,在这么现了这么久了,也只为抛块砖,希望广大程序员同志们提高点安全意识。那累也是值得的。按黄老大的4觉来说这叫:已无明而先觉他。Hehe,把自己说得太伟大了。


不敢爱你,因为我怕我死了之后再也没人像我这么的爱你。
---- H.J.LeoChen 2004/04/07

本文地址:http://com.8s8s.com/it/it24617.htm