JAVA security coding and code auditing

An overview of the

This paper focuses on the basic knowledge of JAVA security coding and code audit. It will introduce the formation of common Web vulnerabilities in JAVA code and corresponding repair schemes by means of vulnerability and security coding examples, and also give examples of some common vulnerability functions.

XXE

introduce

XML document structure includes XML declarations, DTD document type definitions (optional), and document elements. Document Type definitions (DTDS) serve to define the legal building blocks of XML documents. DTDS can be declared within XML documents or referenced externally.

  • Internal declaration DTD:
  • Reference to an external DTD:

When references to external entities are allowed, a malicious attacker can construct malicious content to access server resources, such as reading passwd files:

<? The XML version = "1.0" encoding = "utf-8"? > <! DOCTYPE replace [ <!ENTITY test SYSTEM "file:///ect/passwd">]> <msg>&test; </msg>Copy the code
Hole sample

Here is an example of org.dom4j.io.SAXReader, showing only a snippet of the code:

String xmldata = request.getParameter("data"); SAXReader sax=new SAXReader(); // Create a SAXReader object Document Document =sax.read(new ByteArrayInputStream(xmlData.getBytes ())); Element root= document.getrootelement (); List rowList = root.selectNodes("// MSG "); Iterator<? > iter1 = rowList.iterator(); if (iter1.hasNext()) { Element beanNode = (Element) iter1.next(); modelMap.put("success",true); modelMap.put("resp",beanNode.getTextTrim()); }...Copy the code
The audit function

XML parsing may be used in scenarios such as import configuration and data transfer interfaces. In scenarios involving XML file processing, pay attention to whether the XML parser disables external entities to determine whether XXE exists. Some XML parsing interfaces are as follows:

javax.xml.parsers.DocumentBuilder
javax.xml.stream.XMLStreamReader
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
javax.xml.parsers.SAXParser
org.dom4j.io.SAXReader 
org.xml.sax.XMLReader
javax.xml.transform.sax.SAXSource 
javax.xml.transform.TransformerFactory 
javax.xml.transform.sax.SAXTransformerFactory 
javax.xml.validation.SchemaFactory
javax.xml.bind.Unmarshaller
javax.xml.xpath.XPathExpression
...
Copy the code
Repair plan

When using an XML parser, you need to set its attributes and forbid the use of external entities. For example, SAXReader can be safely used as follows:

sax.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
sax.setFeature("http://xml.org/sax/features/external-general-entities", false);
sax.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Copy the code

For the secure use of other XML parsers, see OWASP XML External Entity (XXE) Prevention Cheat Sheet

Deserialization vulnerability

introduce

Serialization is a means to separate Java objects from the Java runtime environment. It can effectively realize the communication between multiple platforms and persistent storage of objects.

Java programs convert deserialized data to Java objects using the ObjectInputStream object’s readObject method. But when the input deserialized data can be controlled by the user, the attacker can make deserialization produce unexpected objects by constructing malicious input, and execute any constructed code in the process.

Hole sample

The vulnerability code example is as follows:

. InputStream in= request.getinputStream (); ObjectInputStream ois = new ObjectInputStream(in); Ois.readobject (); ois.close();Copy the code

In the above code, the program reads the input stream and deserializes it as an object. At this point, you can check whether commons-Collections 3.1, Commons-Fileupload 1.3.1 and other third-party libraries are available in the project to construct specific deserialized objects for arbitrary code execution. You can refer to ySOserial and MarshalSec for reference.

The audit function

Deserialization operations are generally performed in service scenarios such as template file import, network communication, data transmission, log formatting and storage, object data falling to disk or DB storage. During code audit, we can focus on some deserialization operation functions and determine whether the input is controllable, as follows:

ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject
...
Copy the code
Repair plan

If can clear deserialized object class, can be set up during deserialization white list, for some only provides the interface library can use blacklist Settings are not allowed to be deserialized class or provide the white list interface, through the Hook function resolveClass used to check the class so as to realize the deserialization white list check, sample is as follows:

public class AntObjectInputStream extends ObjectInputStream{ public AntObjectInputStream(InputStream inputStream) throws  IOException { super(inputStream); } /** * Override protected class <? > resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { if (! desc.getName().equals(SerialObject.class.getName())) { throw new InvalidClassException( "Unauthorized deserialization attempt", desc.getName()); } return super.resolveClass(desc); }}Copy the code

You can also use the Apache Commons IO Serialization package ValidatingObjectInputStream accept method to implement the deserialization of a class of white/black list control, if you are using a third-party library upgrade to the latest version. More fixes can be found in Java Deserialization Vulnerability Fixes.

SSRF

introduce

SSRF is formed mostly because the code provides the ability to fetch data from other server applications but does not filter and restrict the target address. Such as getting images from specified URL links, downloading, etc.

Hole sample

This section uses HttpURLConnection as an example. The code snippet is as follows:

String url = request.getParameter("picurl"); StringBuffer response = new StringBuffer(); URL pic = new URL(url); HttpURLConnection con = (HttpURLConnection) pic.openConnection(); con.setRequestMethod("GET"); Con. SetRequestProperty (" the user-agent ", "Mozilla / 5.0"); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; while ((inputLine = in.readLine()) ! = null) { response.append(inputLine); } in.close(); modelMap.put("resp",response.toString()); return "getimg.htm";Copy the code
The audit function

Generally, the operation of initiating HTTP request in the program is to obtain remote pictures, page sharing and collection, etc. During code audit, we can focus on some HTTP request operation functions as follows:

HttpClient.execute HttpClient.executeMethod HttpURLConnection.connect HttpURLConnection.getInputStream URL.openStream .Copy the code
Repair plan
  • Verify HTTP request URLS using whitelists
  • Avoid sending request responses and error messages back to the user
  • Disable unnecessary protocols and limit request ports to only ALLOW HTTP and HTTPS requests

SQLi

introduce

The essence of an injection attack is that the program executes data entered by the user as code. There are two key conditions. The first is that the user can control the input. The second is that the data entered by the user is spliced into the code to be executed. SQL injection vulnerability is a program that splices user input data into SQL statements, so that attackers can construct and change SQL semantics to attack.

Hole sample

Here, the Mybatis framework is used as an example. The sample SQL fragment is as follows:

select * from books where id= ${id}Copy the code

For the audit of SQL injection vulnerability in Mybatis framework, please refer to the aspects of SQL injection vulnerability in Mybatis framework

Repair plan

Mybatis framework SQL statement security should use #{}, avoid dynamic concatenation ${}, ibatis use # variable #. Safe writing is as follows:

select * from books where id= #{id}

Copy the code

File upload vulnerability

introduce

During file uploading, users can upload some Webshell files, such as JSP, because the suffix type of uploaded files is not verified. The code audit can focus on whether there is sufficient security verification for the uploaded file type and whether to limit the file size.

Hole sample

MultipartFile is used as an example. The following is an example code snippet:

	public String handleFileUpload(MultipartFile file){
        String fileName = file.getOriginalFilename();
        if (fileName==null) {
            return "file is error";
        }
        String filePath = "/static/images/uploads/"+fileName;
        if (!file.isEmpty()) {
            try {
                byte[] bytes = file.getBytes();
                BufferedOutputStream stream =
                        new BufferedOutputStream(new FileOutputStream(new File(filePath)));
                stream.write(bytes);
                stream.close();
                return "OK";
            } catch (Exception e) {
                return e.getMessage();
            }
        } else {
            return "You failed to upload " + file.getOriginalFilename() + " because the file was empty.";
        }
    }Copy the code
The audit function

A function in a Java program that involves uploading files, such as:

MultipartFile
...
Copy the code
Repair plan
  • Verify the type and size of uploaded files using whitelists

Autobinding

introduce

Autobinding- Automatic binding vulnerability. This vulnerability has several different names, depending on the language/framework, as follows:

  • Mass Assignment: Ruby on Rails, NodeJS
  • Autobinding: Spring MVC, ASP.NET MVC
  • Object Injection: PHP(Object injection, deserialization vulnerability)

Software frameworks sometimes make it easier for developers to use the framework by allowing them to automatically bind HTTP request parameters to program code variables or objects. This allows an attacker to construct an HTTP request by binding the request parameters to an object, which can produce unexpected results when used by code logic.

Hole sample

The example code takes the demo of Zeronights-Hackquest-2016 as an example to run the justiceleague program. It can be seen that the menu bar of this application consists of four pages: About, Reg, Sign Up and Forgot Password. Our focus is on password recovery, which is how to bypass security issues to verify and retrieve passwords.

1) First look at the reset method, delete the code does not affect the logic. This is easier to understand:

@Controller @SessionAttributes("user") public class ResetPasswordController { private UserService userService; . @RequestMapping(value = "/reset", method = RequestMethod.POST) public String resetHandler(@RequestParam String username, Model model) { User user = userService.findByName(username); if (user == null) { return "reset"; } model.addAttribute("user", user); return "redirect: resetQuestion"; }Copy the code

Here we get username from the parameter and check if there is a user, and if there is, we put the user object into the Model. Because the Controller uses @sessionAttributes (“user”), the User object is automatically added to the session as well. The resetQuestion password retrieval verification page is displayed.

2) resetQuestion resetViewQuestionHandler is displayed on the verification page of password retrieval security question

@RequestMapping(value = "/resetQuestion", method = RequestMethod.GET)
	public String resetViewQuestionHandler(@ModelAttribute User user) {
		logger.info("Welcome resetQuestion ! " + user);
		return "resetQuestion";
	}
Copy the code

Here we use @modelAttribute User User, which is actually getting the User object from the session. The problem is that adding a member variable of the User object to the request changes the value of the corresponding member of the User object. Therefore, when we send resetQuestionHandler a GET request, we can add the parameter “answer=hehe”, so that we can assign a value to the object in the session and change the original password retrieval security question answer to “hehe”. This will enable successful authentication and password retrieval in the last step of security verification

The audit function

This vulnerability generally appears in multi-step processes, such as transfer, secret search and other scenarios, but also pay attention to the following notes:

@SessionAttributes
@ModelAttribute
...
Copy the code

See the Spring MVC Autobinding vulnerability example for more information

Repair plan

Spring MVC can use the @initBinder annotation to set parameters that allow or disallow binding through the WebDataBinder methods setAllowedFields and setDisallowedFields.

URL redirection

introduce

Because Web site sometimes need according to the different logic to users to a different page, such as the typical login interface is often needed after successful authentication will lead users to the login page, before the process if the implementation is bad can lead to the URL redirection problem, a malicious attacker structure jump links, you can ask the user initiated phishing attacks.

Hole sample

This section uses the Redirect of a Servlet as an example. The code snippet is as follows:

String site = request.getParameter("url"); if(! site.isEmpty()){ response.sendRedirect(site); }Copy the code
The audit function

For all the methods of URL redirection in Java programs, pay attention to whether the jump address is verified. The redirection function is as follows:

sendRedirect
setHeader
forward
...
Copy the code
Repair plan
  • Verify the REdirected URL using a whitelist
  • The system displays a security risk warning to the user and asks the user to confirm whether to jump again

CSRF

introduce

Cross-site Request Forgery (CSRF) is an attack that causes a logged in user to perform an action without their knowledge. Because the attacker cannot see the results of the response to the forged request, CSRF attacks are primarily used to perform actions, not to steal user data. When the victim is an ordinary user, CSRF can transfer the user’s funds and send emails without their knowledge. However, if the victim is a user with administrator rights, CSRF may threaten the security of the entire Web system.

Hole sample

Due to the lack of understanding of CSRF, the developer mistakenly regarded “request initiated by authenticated browser” as “request initiated by authenticated user”, and when the authenticated user clicked on the malicious link constructed by the attacker, the corresponding operation was “executed”. For example, a blog removes articles in the following way:

GET http://blog.com/article/delete.jsp?id=102
Copy the code

When the attacker induced the user to click on the link below, if the user’s credentials to the blog site had not expired, he unknowingly deleted the article with id 102. Simple authentication can only guarantee that the request came from a user’s browser, but not that the request itself was voluntarily made by the user.

Vulnerability audit

Such vulnerabilities are generally resolved and fixed in the framework, so when auditing CSRF vulnerabilities. First, we should be familiar with the framework’s protection scheme against CSRF. In general audit, we can check whether there is token, formtoken and other keywords in adding, deleting and modifying requests, and whether the Referer of requests is verified. In manual test, if there is a token or other key, the token value will be replaced with a custom value and the request will be replaced with a custom link or empty the Referer header of the request. Replay the request to see if it can successfully return data to determine if there is a CSRF vulnerability.

Repair plan
  • Referer checks HTTP requests. If the requested address is not in the allowed list, the request will be blocked.
  • Token verification: The server generates a random Token and stores it in the cookie of the current session. When a user initiates a request, the server verifies the random Token. If not, the request is rejected as a forged request.
  • Formtoken verification. Formtoken verification is also Token verification and is valid only in this form request.
  • For high-security operations, you can use secondary verification measures such as verification codes, SMS messages, and passwords
  • Add, delete, or modify requests use POST requests

Command execution

introduce

Due to service requirements, the program may need to execute system commands. However, if the commands executed are controllable by users and services are not restricted, command execution vulnerabilities may occur.

Hole sample

This section uses getRuntime as an example. The code snippet is as follows:

	String cmd = request.getParameter("cmd");
	Runtime.getRuntime().exec(cmd);Copy the code
The audit function

This vulnerability is simple in principle and focuses on finding the function that executes the system command to see if the command is controllable. In some special business scenarios, it is possible to determine whether such a function exists. Here is a typical example scenario. Some program functions require webpage screenshot function, and most of them are implemented using PhantomJS. In most cases, the parameters should be the current URL or relevant parameters obtained from it. In this case, there is a possibility of command execution vulnerability, and some other special scenarios can be imagined by yourself.

The following functions execute system commands in a Java program:

Runtime.exec
ProcessBuilder.start
GroovyShell.evaluate
...
Copy the code
Repair plan
  • Avoid command control by users
  • If you need the user input parameters, the strictly checking for user input, such as, &&, |; Etc.

Access control

introduce

Overreach vulnerability can be divided into horizontal and vertical overreach vulnerability. When the program processes the user’s request, it fails to verify the user’s permission so that the user can access and operate the data of other users with the same role. In this case, it is horizontal overreach vulnerability. If a user with a lower permission can access and manipulate the data of a user with a higher permission, it is vertical overauthorization.

Hole sample
@RequestMapping(value="/getUserInfo",method = RequestMethod.GET) public String getUserInfo(Model model, HttpServletRequest request) throws IOException { String userid = request.getParameter("userid"); if(! userid.isEmpty()){ String info=userModel.getuserInfoByid(userid); return info; } return ""; }Copy the code
The audit function

Horizontal and vertical overreach do not need to pay attention to specific functions, as long as the processing of user operation request to check whether the current login user permissions to determine whether there is a vulnerability

Repair plan

Obtain the current login user and verify whether the user has the current operation permission and verify whether the request operation data belongs to the current login user. The current login user id cannot be obtained from the request parameters that the user can control.

The batch request

introduce

Services often use functions such as sending SMS verification codes, SMS notification, and email notification. If such requests are not restricted, malicious attackers may blast malicious requests in batches. A large number of SMS and email notifications will annoy normal users and consume company resources.

In addition to SMS, mail bombing, another is also need to pay attention to, there may be many in the program interface, used to query whether there is any, account name, account and phone or email, name, etc, the matching relation between such requests such as do not limit will be malicious users to use bulk, so as to get the user data relations related data. For this kind of request, we can pay attention to whether there is authentication and restriction on the request during code audit to roughly judge whether there is risk.

Hole sample
@RequestMapping(value="/ifUserExit",method = RequestMethod.GET) public String ifUserExit(Model model, HttpServletRequest request) throws IOException { String phone = request.getParameter("phone"); if(! phone.isEmpty()){ boolean ifex=userModel.ifuserExitByPhone(phone); if (! Ifex) return "user does not exist "; } return "User registered "; }Copy the code
Repair plan
  • Limit the frequency, hourly, and daily volume of such requests from the same user on the server, but not on the front end

Third-party Component Security

introduce

This is easier to understand, as Struts2, insecure editing controls, XML parsers, and third-party components that can be exploited by other vulnerabilities such as Commons-Collections :3.1 can be checked for imported dependencies in the program poM file. Unsafe versions should not be used even if they are not used in the code or are difficult to exploit directly. The life cycle of a product is so long that it is difficult to guarantee that vulnerabilities will not be introduced later that can be exploited.

Repair plan
  • Use the latest or secure version of third-party components

To be continued…

conclusion

In addition to the vulnerabilities mentioned above, some special vulnerabilities are sometimes encountered during code audit, such as the development of some security check functions closed for the convenience of testing, and even some reserved backdoors and test management interfaces that have not been completely cleared. In addition, the security of the framework itself can also be deeply dug. Some security checks, security solutions are not necessarily flawless, even if there are some security solutions, but whether the developer has used the security solution and whether the correct use of security solutions are possible problems. Large companies have mature frameworks, and there are not many basic security issues, but security and process-related issues at the design level are largely dependent on development experience. For process-related vulnerabilities, it is necessary to be familiar with the design and logic of the application itself, which are also potential risk points.

Don’t expect a developer to write safe code by saying, “All input is untrusted.” Show me the code