Web安全之语法知识补习

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,或者,SYSTEMPUBLIC


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
发布了30 篇原创文章 · 获赞 13 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/u013224189/article/details/49620295