隐藏Nginx和PHP版本号

配置完一台服务器后,并不是就可以高枕无忧了,前不久刚刚爆发的PHP 5.3.9版本的漏洞也搞得人心惶惶,所以说经常关注安全公告并及时升级服务器也是必要的。一般来说,黑客攻击服务器的首要步骤就是收集信息,比如说你的软件版本,这些将成为下一步有针对性攻击的依据。所以说一定程度的隐藏这些信息就显得非常有必要了,本文将简单介绍如何在网络上隐藏Nginx版本号以及PHP的版本号。

1.隐藏Nginx版本号,Nginx的版本号主要在两个地方会有,一个是HTTP header,有个Server:nginx/1.x.x类似会暴露Web服务器所用软件名称以及版本号,这个也是大多数Web服务器最容易暴露版本号的地方,第二个地方是Nginx出错页面,比如404页面没有找到等,这是如果用户没有指定页面的话,那么Nginx自己的页面会有版本戳记。

不过幸运的是对于这两个地方的版本号隐藏,Nginx都提供了简单的办法一步到位,参考server_tokens。通过在配置文件的http节配置server_tokens off来达到我们目的。

继续阅读“隐藏Nginx和PHP版本号”

关于CSDN密码泄露事件的一点感想

今天看到这条消息顿时心凉了半截,自己有账号在CSDN,据朋友发来的消息讲我的账号貌似也中枪了。不过好在CSDN的密码和我大部分密码不一样,而且特别重要的账户都采用KeePass随机密码管理起来了,所以在其他账户安全上面影响不大,唯一的问题是邮箱的泄露,600万账户目标用户非常明确,都是IT人员,所以这给垃圾邮件者带来了福利,这下苦了我们这些IT者,每天加班加点也就算了,被用户骂也就算了,没想到这点隐私还被泄露,CSDN的官方道歉信也已经出来了,但又有什么用呢?除了更改相关密码,特别是连带账户密码外,做好迎接垃圾邮件已经隐私泄露的准备吧。怎么说呢,国内很多企业对于信息安全还是相当漠视的,部分从业者也处于一种做好份内事情的状态,没有责任心,当然也不能怪人家,国内的福利薪酬或者超负荷工作问题导致了大家都无力去认真做好一些事情,甚至有些企业为了压缩成本还让一人身兼多职,既是程序员又是设计师还是测试员,这样产品的质量就显而易见了。由于上述种种原因就导致了这个泄露事件那个泄露事件什么的,更有甚者拿客户资料去谋取利益。我之前实习的一家企业客户资料就很随意,因为公司人手少,大家天天忙得半死,根本没人去关心这些信息的安全问题。之前我发现国内某域名注册商网站存在客户资料泄露风险,和他们在线客服联系了好久都没有重视起来,直到近1个星期,打电话到其总部,沟通了很久,他们才重视并修复了漏洞。说到底还是人的原因,更多的是企业本身的原因,不能因为节约了成本就精简了人手,那么点钱就让程序员天天为你累死累活,迟早会出问题的。

继续阅读“关于CSDN密码泄露事件的一点感想”

ASP上传漏洞之利用CHR(0)绕过扩展名检测脚本

本文部分脚本具有攻击性,仅供学习研究用,请用在合法合理范围内,对造成的损失本人不承担责任,本人也不提供黑客攻击技术指导。

今天Demon提到了这个问题,正好想到之前看到的一篇文章《Automatic file upload using IE+ADO without user interaction – VBSscript》。这篇文章给出了本地无交互自动上传脚本的示例,正好今天可以借来一用,原脚本利用了InternetExplorer.Application组件,我改写了一下,用WinHttp.WinHttpRequest.5.1实现了类似的功能,关于这个组件更多的用法请参考《WinHttpRequest Object Reference》

继续阅读“ASP上传漏洞之利用CHR(0)绕过扩展名检测脚本”

ASP/VBScript中CHR(0)的由来以及带来的安全问题

CHR(0)是个特殊的字符,当然在Visual Basic或者VBScript中可以直接用vbNullChar表示,从数值意义上来说这个字符就是数字0。该字符标识着字符串的结束,也称作null-terminated,这个给脚本编程尤其是ASP编程带来了一定的麻烦,很多人可能会问为什么要保留这个特殊字符,我们可以追溯到编写操作系统的语言之一C语言,学过C/C++的童鞋可能知道,在字符串中标识一个字符串结束靠的就是结尾的\0(NULL或者0),否则不能称作为字符串,只能说是字符串数组,任何对于字符串操作的函数如果传入的字符串丢掉了这个结束NULL字符,都有可能会出现异常。

char strbuf[] = "Hello"
// 等价于
char strbuf[] = {'H', 'e', 'l', 'l', 'o', '\0'}

字符串长度的判断函数简单的实现之一:

size_t strlen_a(const char * str) {
  size_t length = 0;
  while (*str++ )
    ++length;
  return length;
}

继续阅读“ASP/VBScript中CHR(0)的由来以及带来的安全问题”

程序处理用户输入过滤不严导致BUG及安全问题

这算是个老生常谈的问题了,我前面的文章也提到了由此导致的SQL注入漏洞或者XSS跨站漏洞,总结了一下,对于Web有4大漏洞是需要严肃对待的,比如SQL注入、XSS跨站另外还有上传漏洞以及对URL地址处理不严导致的越权漏洞,这个改天单独开一篇文章介绍一下,下面继续谈用户输入过滤不严导致的问题,前天正好帮一个客户处理一个程序问题,一个10年前的计票程序,当然不是我开发的,所以处理起来非常棘手,主要是计票汇总时程序出现了崩溃,仔细研究了这个程序的开发语言,发现是用PowerBuilder构建的,而且留下了PBL文件,用PowerBuilder分析了这个文件,大概知道了BUG的位置。查看了之前录入的数据,发现有个别票选项是0,该软件使用说明上注明只能使用1~4选项,那么说0就是非法的数据选项,那么这个汇总导致程序崩溃的Bug很有可能是由于这个导致的,删除了所有的0选项票,然后再汇总,一切正常!为了切实说明导致Bug的原因,我尝试重现了这个问题,开启一张新选票,然后输入某被选举人票数,输入过程故意输错一项,然后再尝试清除,结果发现无法清除,将该选项设置为0则程序提示“必须为1~4数字”,但是不对0这个无效数据做出处理,也就是说0依旧存在,下一步汇总,结果崩溃如愿的发生了,总结一下,初步判断该程序为“赶工”产品,后期测试不足,所以导致该隐性Bug没有能及时发现。

同样的问题依旧出现在某些网站上,比如经典的SQL注射漏洞,以SQL Server的Transact-SQL语言为例,我们就需要过滤一些危险的字符,比如像单引号,在SQL Server中,如果字符串包含单引号,我们就必须将其转换为两个单引号,避免可能的错误和已知的攻击,参考微软官方的《SQL 注入》(SQL Injection)文章,提供下面一个转换单引号的VBScript函数:

继续阅读“程序处理用户输入过滤不严导致BUG及安全问题”

Linux/VPS环境下Nginx安全配置小记(1)

关于Nginx介绍我就不多说了,下面主要记录一下我所收集的一些有用的配置,多数是和服务器安全相关的。以下部分参考了nixCraft上的《Top 20 Nginx WebServer Best Security Practices》这篇文章很有借鉴意义,详细讲解了Linux+Nginx服务器安全的方方面面,这篇文章的中译版叫《20个Nginx Web服务器最佳安全实践》,大家可以搜索一下。

1. 删除不需要的Nginx模块

我们可能根据我们的需要配置Nginx,当然在编译时可以选择某些不需要的模块不编译进去,比如精简掉autoindex和SSI模块,命令如下:

1
2
3
./configure --without-http_autoindex_module --without-http_ssi_module
make
make install

当然在编译前可以通过下面的命令查看那些模块是可以开启或者关闭的:

1
./configure --help | less

2. 修改Nginx服务器名称和版本号

著名的NETCRAFT网站可以很轻松的查到你服务器的操作系统和服务程序版本,或者HTTP Response Header也能向我们透露这些信息,很多情况下,这些信息将为黑客进行攻击提供依据,因此我们需要对其进行伪装。

继续阅读“Linux/VPS环境下Nginx安全配置小记(1)”

由获取的IP地址数据校验不严格导致XSS以及SQL注入的安全漏洞

不久前看到WAVDB上一篇《BlueCMS信息门户系统存在getip()注射漏洞》,让我感觉到WEB编程中安全隐患处处都会存在,往往很多情况下都是我们大意,导致问题的产生,经典的安全问题就是SQL注入攻击(SQL Injection Attack)以及XSS跨站脚本攻击,这些安全问题说到底就是对用户数据校验不严格所造成的,经典的安全编程模式应该是脱离程序员假定的数据格式,要能够接受来自客户任何数据,然后对这些数据进行甄别,过滤掉不符合原假定格式的数据,因为这些数据可能是无用的或者是有害的,说到底,大部分安全问题还是由于对来自用户数据的不严格判断过滤所导致的。

下面再来看看BlueCMS的getip()安全漏洞,原有的代码摘录如下:

继续阅读“由获取的IP地址数据校验不严格导致XSS以及SQL注入的安全漏洞”

安全的校验Session验证码并避免绕开验证码攻击

已经记不得是在哪个网站上看到的了,一般情况下对于验证码的校验,大家很容易写成下面这样:

1
2
3
4
5
6
7
<%
If Request.Form("SecurityCode") = Session("SecurityCode") Then
  ' TODO : Database operations
Else
  Response.Write "Security code incorrect!"
End If
%>

验证码图片产生Session(“SecurityCode”)并保存正确的验证码值,然后获得用户提交的验证码值,然后两个一比对如果一样则表示验证码正确,否则验证码错误。表面上这样的算法没有什么问题,但是对于一种特殊情况则会让验证码形同虚设。

首先我们知道,对于上面的算法有个核心的地方就是我们要访问产生验证码图片的那个文件才会有个保存验证码值的Session,然后才能对用户的输入进行正确的比对,假如有心人构造一个绕开验证码图片文件的Form然后进行提交会得到什么呢?Session(“SecurityCode”)不存在为空,如果此时用户验证码什么都不输入,这时验证码校验就形同虚设了。好,这里利用漏洞攻击的关键就是验证码的Session,我们很容易就能够让服务器不产生这个Session从而使这样的攻击变成可能。

解决的方法也很容易,校验验证码的Session是否为空或者校验用户输入的验证码是否合法,构造安全表单的关键就是永远不要相信用户的输入。下面采用校验验证码Session和用户输入的双保险办法解决这个安全问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
' str为要校验的验证码,len为验证码长度
Function IsSecurityCodeValid(str, len)
  IsSecurityCodeValid = Not CBool( _
    IsEmpty(str) Or CStr(str)="" Or Len(str)<len)
End Function
 
If IsSecurityCodeValid(Request.Form("SecurityCode"), 4) AND _
   IsSecurityCodeValid(Session("SecurityCode"), 4) AND _
   Request.Form("SecurityCode") = Session("SecurityCode") Then
  ' TODO : Database operations
Else
  Response.Write "Security code incorrect!"
End If

END

利用链接URL的GET方式删除记录操作的安全隐患

最近在研究ASP.NET的MVC3,在asp.net的系列讲解中了解到一个有趣的安全问题,Stephen Walther已经在其《ASP.NET MVC Tip #46 – Don’t use Delete Links because they create Security Holes》文章中做了相关描述,基本的意思就是我们常常在设计信息系统时往往会很随意的将Delete记录这个操作设计成一个链接,通过这个链接以GET的方式传入要删除记录的ID,然后服务器处理脚本或程序就会删除我们所指定ID的记录,这听起来没有什么问题,但是有一种情况是存在的。

假设删除记录的URL是http://wangye.org/Sample/Delete/23,其中Delete后面的23表示要删除记录的ID,好,目前的状态是只要我们不去访问这个URL,那么这条ID为23的记录就是安全的,这时骇客想要删除这条记录,他们往往会发给你一封邮件,内容的源代码如下:

1
<img src="http://wangye.org/Sample/Delete/23" />

当你打开这封邮件时,虽然http://wangye.org/Sample/Delete/23不是一个图片,但是你的计算机仍然会Request这个地址,那么造成的后果是什么呢,ID=23的这条记录被删除了,很显然这个不是我们所期望的,但是骇客们往往就这样做到了,不过做到这个还要有两个前提:1.知道操作删除的URL地址和格式。2.获得访问权限。目前大多数删除操作是在访问权限控制之下的,但是如果我们在登录系统并获得访问权限后再打开那封问题邮件,那么这道防线就形同虚设了。

Stephen Walther提出的解决方案就是避免使用GET方式进行删除操作,当然通常情况下HTML只能支持GET和POST操作,所以很自然的就想到采用POST来取代GET进行相关操作,是的这不失为一个好的办法,不过HTTP除了POST和GET还有另外的操作方式,比如PUT和DELETE等,在HTTP中GET、POST、PUT、DELETE就对应着对这个资源的查、改、增、删4个操作,当然要实现DELETE操作还是要借助于JavaScript脚本,比如Ajax删除。在MVC中的Controller里的处理删除的方法前面加上[AcceptVerbs(HttpVerbs.Delete)]标识,表示仅接受DELETE操作。

然后前端脚本可以像下面这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script type="text/javascript">
  function deleteRecord(recordId)
  {
    // Perform delete
    var action = "/Home/Delete/" + recordId;
 
    var request = new Sys.Net.WebRequest();
    request.set_httpVerb("DELETE");
    request.set_url(action);
    request.add_completed(deleteCompleted);
    request.invoke();
  }
 
  function deleteCompleted()
  {
    // Reload page
    window.location.reload();
  }
</script>
<a onclick="deleteRecord(23)" href="javascript:void(0)">Delete 23</a>

通过上面的脚本就可以利用DELETE方法就可以安全的向服务器发出删除ID=23这条记录了。当然如果你不希望采用JavaScript方式的话那只有通过表单的POST形式进行删除了,至于ID,可以放在type=hidden的input控件里。

网页文字禁止复制与解决方法

原文发表于2009年4月12日 标题是《解除某些网站文字不能复制的问题》

经常在查阅某些网站时会出现文字无法复制的问题,其实是这些网站通过JavaScript脚本做了一定限制,我们可以通过下面的代码解除这个限制:

javascript:with(document.body){oncontextmenu='';ondragstart='';onselectstart='';onselect='';oncopy='';onbeforecopy='';onmouseup='';}void(0);

以上代码为一行,具体用法是打开那个不能复制文字的网页,然后全选地址栏网址,删除全选的网址,再将这段代码粘贴到地址栏中,注意前面不要留空格(即必须以javascript开头),最后回车。然后你就会发现网页的内容就能复制了。

2011年3月29日更新

这段代码的原理是什么呢?我们先谈谈如何限制或者禁止浏览者复制网页上的文字,正常的防止浏览者复制文字,我们肯定是想到禁用用户的某些特定的操作,比如鼠标右键,选择,复制等等,而这些操作对应了相应的脚本事件,只要给这些事件加上一个方法,让其返回false就可以“吃”掉这个操作了,一般的禁止复制的脚本代码如下:

1
2
3
4
5
6
7
8
with(document.body) {
  oncontextmenu=function(){return false}
  ondragstart=function(){return false}
  onselectstart=function(){return false}
  onbeforecopy=function(){return false}
  onselect=function(){document.selection.empty()}
  oncopy=function(){document.selection.empty()}
}

无非就是禁止了类似于oncontextmenu(鼠标右键菜单)、onselectstart和onselect(禁止选择)等等,所以找到问题的根本,就可以用上面讲的办法清空这些return false的函数了,清空后就可以复制了。

写在最后

禁止用户复制网页上的文字还有禁止鼠标右键什么的是极其糟糕的做法,违反了用户体验的根本原则,这样做让用户容易反感进而不再回访你的网站,访客忠诚度也是衡量一个网站成功与否的重要标志之一,所以要留住用户,设计必须以用户为中心。更何况这些小伎俩也很容易破解,比如另存网页,禁用脚本,查看源代码等等,所以还是不要做限制为好。

2012年4月9日更新

通常情况下我们可能不想这么复杂的解决这类问题,比如说某网页文字无法复制,网页无法右击等等限制,我们可不希望慢慢的找到这段代码,然后选中,然后复制,然后粘贴,然后按回车,简直太麻烦了。接下来我将介绍个简单的利用上面这段代码的办法,那就是对下面这个链接右击,在菜单中选择添加到收藏夹:

点击解除网页限制

这样,下次再遇到受限的网页页面时就可以直接打开收藏夹,然后点下你添加的“点击解除网页限制”就可以了,怎么样,够简单的吧。