preface

I am participating in the 2022 Spring Recruitment series – experience review, click here for more details.

A few days ago, dasmarty’s three-year-old app was scanned for a vulnerability, Thought to increase the X – the content-type head can perfectly solve the Options security vulnerabilities (see great wisdom to teach you to learn Java | Spring Boot project set X – the content-type – Options response headers), wildest dreams, Since x-Content-type-options has been added to nosniffing headers, there has been a major problem.

A bumpy road to resolution

Problem description and cause

In your application, you have a page where you need to make an Ajax call to the interface in the background to get the data (jSONP is used in Ajax to solve the cross-domain problem because cross-domain is involved in production), But adding the X-Content-Type-options response header caused Ajax to fail. X-content-type-options: nosniffing problem with response headers (since there have been major problems since the addition of response headers) ๐Ÿ‘‡

$(document).ready(function(){
console.log("Begin the request.");
	$.ajax({
		 url:"http://localhost:8081/searchweb/search/hotWord",
		 type : 'get',
		 cache : false,
		 async : true,
		 dataType : "jsonp",
		 timeout:30000,
		 jsonpCallback:"callback",
			 processdata:false,
		 data:{
			 siteid:"97",
		 },
		 success: function(jsonData){
			console.log("Request successful");
			console.log("jsonData:"+jsonData);
			
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			   console.log("Status code:+XMLHttpRequest.status);/ / status code
			   console.log("State:"+XMLHttpRequest.readyState);/ / state
			   console.log(Error message:+textStatus);// Error message}}); })Copy the code
@RequestMapping(value = "/search/hotWord", method = RequestMethod.GET ,produces="application/json; charset=UTF-8,text/html; charset=UTF-8")
@ResponseBody
public JSONPObject hotWord(HttpServletRequest request, HttpServletResponse response, @RequestParam int siteid, @RequestParam String callback){
	
	List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
	if(siteid == 97){
		list = searchService.listHotWords(0);
		Map<String, String> map = new HashMap<String, String>();
		for(int i = 1; i <=4; i++ ){ map.put("word_"+i, (String) list.get(i).get("words"));
		}
		System.out.println("map --->"+JSON.toJSONString(map));
		return new JSONPObject(callback, map);
	
	}else{
		list = searchService.listHotWords(5);
		Map<String, String> map = new HashMap<String, String>();
		for(int i = 1; i <=4; i++ ){ map.put("word_"+i, (String) list.get(i).get("words"));
		}
		return newJSONPObject(callback, map); }}Copy the code

As expected, x-Content-Type-options: Nosniffing header has been added, leading to the above problems. Later, Baidu found the root cause of the problem ๐Ÿ‘‡

  • If a “Nosniff” command is received in the response retrieved from the styleSheet reference, Windows Internet Explorer will not load a “styleSheet” file unless the MIME type matches “text/ CSS “.
  • If a “Nosniffing” instruction is received in a response retrieved through a Script reference, Internet Explorer will not load a “script” file unless the MIME type matches one of the following nine values: “Application/ecMAScript” “Application /javascript” “Application /x-javascript” “Text/ecMAScript” “text/javascript” “text/j Script “, “text/x-javascript”, “text/ VBS “, “text/vbscript”

Now that the root cause of the problem is known, let’s begin to solve it ๐Ÿ’ช

solution

As the saying goes, “Trivial problems have a creepy solution”, we can use a most “creepy” method to solve this problem, delete x-Content-Type-options: nosniff response header, obviously this method is not feasible, everyone friends as a joke look at the line ๐Ÿ˜‚

If the content-type value is application/json, it will not match any of the nine values listed above. Replace it with a value that meets the requirements of the project and satisfies one of the above nine types. For the above interface, the return value of the interface does not have to be in Json format. The return value of the interface can also be a String, so we can use text/javascript instead of application/ Json. Let’s look at the error message thrown by the browser: Callback was not called; callback was not called; Jsonp callback was not called; Jsonp callback was not called. Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp: Jsonp This brings us to the final step of solving the problem – add a line of code to the interface to solve the cross-domain problem: response.setheader (” access-Control-allow-origin “, “*”).

The complete code

โœŒ we can’t load because of adding security header X-content-type-options. โœŒ -we have fun. ๐Ÿ‘‡

$(document).ready(function(){
console.log("Begin the request.");
	$.ajax({
		 url:"http://localhost:8081/searchweb/search/hotWord",
		 type : 'get',
		 cache : false,
		 async : true,
		 dataType : "json",
		 timeout:30000,
		 data:{
			 siteid:"97",
		 },
		 success: function(jsonData){
			console.log("Request successful");
			console.log("jsonData:"+jsonData);
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			   console.log("Status code:+XMLHttpRequest.status);/ / status code
			   console.log("State:"+XMLHttpRequest.readyState);/ / state
			   console.log(Error message:+textStatus);// Error message}}); })Copy the code
@RequestMapping(value = "/search/hotWord", method = RequestMethod.GET ,produces = "text/javascript; charset=UTF-8")
@ResponseBody
public Object hotWord(HttpServletRequest request, HttpServletResponse response, @RequestParam int siteid){
	
	List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
	if(siteid == 97){
		list = searchService.listHotWords(0);
		Map<String, String> map = new HashMap<String, String>();
		for(int i = 1; i <=4; i++ ){ map.put("word_"+i, (String) list.get(i).get("words"));
		}
		response.setHeader("Access-Control-Allow-Origin"."*");     // Allow cross-domain requests
		return JSON.toJSONString(map);
	}else{
		list = searchService.listHotWords(5);
		Map<String, String> map = new HashMap<String, String>();
		for(int i = 1; i <=4; i++ ){ map.put("word_"+i, (String) list.get(i).get("words"));
		}
		returnJSON.toJSONString(map); }}Copy the code

summary

My experience is limited, some places may not be particularly in place, if you think of any questions when reading, welcome to leave a message in the comments section, we will discuss one by one ๐Ÿ™‡

Please take a thumbs up and a follow (โœฟโ—กโ€ฟโ—ก) for this article ~ a crab (โ—’โ—ก’โ—)

If there are mistakes in the article, welcome to comment correction; If you have a better, more unique understanding, you are welcome to leave your valuable ideas in the comments area.

Love what you love, do what you do, listen to your heart and ask nothing