getRequestDispatcher 和sendRedirect区别
125 String url = req.getRequestURL().toString();
126
127 RequestDispatcher disp = req.getRequestDispatcher(url.substring(url.lastIndexOf("WebGoat/")
其中getRequestDispatcher是服务器内部跳转,地址栏信息不变,只能跳转到web应用内的网页。
而sendRedirect是页面重定向,地址栏信息改变,可以跳转到任意网页。
Xpath注入
37 sb.append("/Employees/Employee [Managers/Manager/text()='" + userId + "']/Salary ");
39 String expression = sb.toString();
40 System.out.print("expression:" + expression);
41 nodes = (NodeList) xPath.evaluate(expression, inputSource,XPathConstants.NODESET); //sink点
evaluate() 方法计算一个 XPath 表达式,返回一个Xpathresult对象。
SQL注入
为什么java中preparedstatement为什么可以防止sql注入?
用preparedstatement就会把sql的结构给数据库预编译。对 于 JDBC而言, SQL注入 攻 击 只 对 Statement有效, 对 PreparedStatement 是无效的, 这 是因 为 PreparedStatement 不允 许 在不同的插入 时间 改 变查询 的 逻辑结 构。
List result = query.list() //source 是什么意思?
Hibernate的HQL语句返回的是一个QUery对象,将Query对象query转换成集合,并且把该集合赋值给一个新的集合。result将被视为不可信数据,因为无法确定数据库里面的数据是否是来自用户输入。
execute、executeUpdate、executeQuery三者的区别(及返回值) //sink
1. ResultSet executeQuery(String sql); 执行SQL查询,并返回ResultSet 对象。
2.int executeUpdate(String sql); 可执行增,删,改,返回执行受到影响的行数。
3. boolean execute(String sql); 可执行任何SQL语句,返回一个布尔值,表示是否返回ResultSet 。
stmt.executeUpdate(String sql)是Statement 接口中的方法
executeUpdate(String sql)
执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句,如果sql语句包含不可信赖数据,可能在此导致sql注入等问题。
BufferedReader.readline()读取的数据是不可信的?
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), UTF8));
String s = br.readLine() //sink
BufferedReader.readline()一般是读取文件的数据,而从数据库、文件或者其他容器获取的数据都不视为安全数据。
因此,如果将s直接用于sql语句,就可能造成sql注入等问题。
104 public Boolean executeSQL(String sql) {
105 try {
106 String[]s=sql.split(Constants.ONESQL_PREFIX);
107 for(String sqls:s){
108 if(StringUtils.isNotBlank(sqls)){
109 getJdbcTemplate().execute(sqls.trim()); //sink
110 }
getJdbcTemplate().execute引出的知识
Spring JDBC框架提供以下几种模板类来简化JDBC编程,如JdbcTemplate。
JdbcTemplate主要提供以下五类方法:
execute():可以用于执行任何SQL语句,一般用于执行DDL语句;
update()及batchUpdate():update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
query()及queryForXXX():用于执行查询相关语句;
call():用于执行存储过程、函数相关语句。
/**
* 预编译语句设值回调使用
* 通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql
*/
public void preparedStatementSql() {
String sql = "insert into tab_item values(?,?,?)";
int row = getJdbcTemplate().update(sql, new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1, 101);// JDBC占位符集合的序号是从1开始的,而不是0
ps.setObject(2, "Apple");
ps.setString(3, "Ipad4");
}
});
Assert.isTrue(row == 1, "插入失败");
// JdbcTemplate也提供一种更简单的方式设值相应的占位符位置的值
sql = "delete from tab_item where id = ?";
row = getJdbcTemplate().update(sql, new Object[] { 101 });
Assert.isTrue(row == 1, "删除失败");
}
sqls.trim()
SQL 中的 TRIM 函数是用来移除掉一个字串中的字头或字尾。最常见的用途是移除字首或字尾的空白
例:
SELECT TRIM(' Sample ');
结果:
'Sample'
String sqls:s
获取s中所有的sql语句
12 import org.apache.struts.action.ActionForm;
249 public ActionForward toHVPSRecvPZPPrint(ActionMapping mapping,
250 ActionForm form, HttpServletRequest request,
251 HttpServletResponse response) throws Exception {
252
253 PS pps = (PS) this.getBean("PS");
255 PForm voform = (PForm) form;
256 PEntity ppe = voform.getPo(); //sink
...
261 Systemusersmanage user = (Systemusersmanage) request.getSession()
262 .getAttribute("userentity");
263 ppe.setPrinter(user.getUsername());
...
268 List list = pps.queryBatchPZHvps(ppe);
Struts框架利用ActionForm对象来临时存放视图页面中的表单数据。ActionForm用于封装用户的请求参数,而请求参数是通过JSP页面的表单域传递过来的,因此voform.getPo()的值来源于不可信赖源。
import com.ban.form.systemManage.SystemorganizationscustomForm;
buf.append(" AND Number='"+ systemOrganizationscustomForm.getBankNumber() + "'"); //sink
systemOrganizationscustomForm.getBankNumber() 这个地方引入了不安全数据,一开始真没有看出来。后来仔细查看代码才发现 systemOrganizationscustomForm 继承自ActionForm。
A.java
public class BaseActionForm extends ActionForm {
}
B.java
public class SystemorganizationsmanageForm extends BaseActionForm {
}
跨站脚本
response.getWriter()响应信息通过out对象输出到网页上,当响应结束时它自动被关闭。
50 ServletOutputStream out = response.getOutputStream();
51 out.write(file.getContent());
将获取的数据输出到页面上;
如果数据包含污点数据,就有可能造成跨站脚本。应该在输出前对内容进行输出编码。
JSP中System.out.println()与out.println()区别
out.println()输出到客户端。
在out.println()中,out是response的实例,是以response为对象进行流输出的,即将内容输出到客户端。如果在JSP页面中使用System.out.println(),在客户端只会输出一个空格。
System.out.println()打印在控制台当中。
System.out.println()用的是标准输出流,这个是输出在控制台上的,而JSP不是控制台程序。不管是在JSP还是在JAVA程序中,System.out.println()都是打印在控制台上。 如果想打印在页面,简单点的方法是:
out.print( “要打印的内容” );
entity = (T) getSession().get(getEntityClass(), id) //source
这个是hibernate的api, hibernate 是操作数据库的一个框架。从数据库、文件或者其他容器获取的数据都不视为安全数据。因此,如果将entity的数据直接传递输出到页面,就有可能导致跨站脚本等问题。应该在输出前对内容进行输出编码。
XML外部实体注入
164 inputSource = new InputSource(is);
165 entity = (CommonXMLEntity) unmar.unmarshal(inputSource); //sink
unmarshal()是把xml对象转化为我们需要的java对象的方法。为了避免XXE注入,请勿将直接处理XML源的unmarshal方法用作java.io.File、java.io.Reader或java.io.InputStream。
防止XML外部实体注入的方法:
1.使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
2.过滤用户提交的XML数据
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
...
in.readFully(inb, 0, len); //source
String recven = rb.getString("recven").trim();
returnString = new String(inb, recven);
in.readFully(inb, 0, len)也被视为一个不可信数据来源,原来问题出在 in 本身。
文件泄露
程序接收不可信数据,并使用其构造服务器转向所使用的路径,可能导致查看受保护的目录下的任意文件,甚至下载应用程序的二进制代码或者jar文件。
如黑客使用"http://www.yourcorp.com/webApp/logic?returnURL=WEB-INF /applicationContext.xml"
将能够查看该应用程序的applicationContext.xml文件。
修复建议:避免通过用户输入构建服务器重定向路径。当完全不能避免时,应该对不可信的用户输入进行验证。还可以创建一份合法的安全字符串列表,限制用户只能输入该列表中的数据。
super的几种用法
------------------------------
在Java中,有时还会遇到子类中的成员变量或方法与超类(有时也称父类)中的成员变量或方法同名。因为子类中的成员变量或方法名优先级高,所以子类中的同名成员变量或方法就隐藏了超类的成员变量或方法,但是我们如果想要使用超类中的这个成员变量或方法,就需要用到super.
-----------------------------
class Country {
String name;
void value() {
name = "China";
}
}
class City extends Country {
String name;
void value() {
name = "Hefei";
super.value();//不调用此方法时,super.name返回的是父类的成员变量的值null
System.out.println(name);
System.out.println(super.name);
}
public static void main(String[] args) {
City c=new City();
c.value();
}
}
------------------------------
用super直接传递参数:
------------------------------
public class Chinese extends Person {
....
Chinese() {
super(); // 调用父类构造函数(1)
prt("A chinese.");// (4)
}
Chinese(String name) {
super(name);// 调用父类具有相同形参的构造函数(2)
prt("his name is:" + name);
}
}
拒绝服务
readInt是输入流中的读取下一个整数的意思
如果输入的是非整数,会抛出异常。 read读取数据过大时,可能造成拒绝服务等攻击。
34 int len = readInt(); //source
...
200 while ((i = read(ba, 2 + bytesRead, len - bytesRead)) > -1 //sink
getInitParameter()方法是在GenericServlet接口中新定义的一个方法,用来调用初始化在web.xml中存放的参量。一般我们写servlet都是用HttpServlet类来写,它是实现了GenericServlet接口,所以它就有getInitParameter()方法。调用格式为:
String name = getInitParameter(“name”); 或
String name = getServletConfig().getInitParameter(“name”);
例:
160 String dbStr = getInitParameter("hsqldb.server.database"); //source
Integer.getInteger(String)的功能是根据指定的名称得到系统属性的整数值。第一个参数将被认为是系统属性的名称,系统属性可以通过 System.getProperty(java.lang.String)方法访问得到。属性值字符串将被解释成一个整数,并且以表示这个值的Integer对象形式返回。
1513 retries = Integer.getInteger(HsqlDatabaseProperties.system_lockfile_poll_retries_property,
retries).intValue(); //source
HTTP消息头注入
String attchmntnm = request.getParameter("attchmntnm"); //source
response.setHeader("*****","attachment;filename=\""+attchmntnm+"\""); //sink
http://www.normal.com/somepage.php?page=%0d%0aContent-type:text/html%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type:text/html%0d%0a%0d%0%3Chtml%3EHacker Content%3C/html%3E