Traffic was hijacked
There are two types of traffic hijacking
-
Domain name resolution hijacking
-
Data hijacking (HTTP hijacking)
Our domestic users, to visit a website, there will be three steps
- First, access the DNS server and convert the domain name to an IP address
- Access this IP address so you can access the target web site
- If it is a well-built website, it will generally put the static resources on the HOUSE CDN
Traffic hijacking is a kind of behavior in which data is stolen, tampered with, or even attacked by forwarding traffic
DNS hijacking
Domain name resolution hijacking (DNS hijacking) is a common hijacking method for traditional DNS resolution. When a user enters a web address in a browser, that is, sends an HTTP request, domain name resolution is performed to obtain the IP address of the service server. When traditional DNS resolution is used, the DNS server provided by the local network carrier is used to obtain the resolution result. A problem occurs when a user requests the local DNS server to resolve the domain name. The target domain name is maliciously resolved to another IP address. As a result, the user cannot use the service.
attacks
So how can you contaminate DNS for traffic hijacking purposes? Roughly speaking, there are three approaches:
-
On the user’s device: this is mainly through some malicious software, for example, some early rogue software will tamper with the hosts file on the user’s local computer, affecting the user’s search engine work.
-
Contamination of intermediate link devices: DNS queries are sent in plaintext based on UDP. Therefore, man-in-the-middle attacks can affect DNS results by modifying UDP packets on any intermediate devices, such as routers.
-
Hacking DNS servers: This is a costly solution that may seem difficult, but DNS is a relatively old technology, and the implementation of the service software may have fallen into disrepair. Attackers with ulterior motives can find DNS servers that are poorly maintained and attack them. In addition, sometimes not only THE DNS software is running on the DNS server, but also some other software, such as the HTTP service, is running at the same time. In this case, attackers can control the server through the vulnerabilities of these software, thus affecting the DNS resolution. Due to DNS cache and up-down transfer, once a DNS server is affected, the access of many users is affected at a time, which is very dangerous.
Of these three approaches, the first and the third have high implementation costs, but polluting link devices is the easiest way to succeed in today’s days when Wi-Fi is widespread and security awareness is not yet widespread.
Defense strategy
At present, there are many researches on DNS poisoning and man-in-the-middle attack. The SECURITY of THE DNS protocol is poor, and it is difficult to modify the DNS protocol. Therefore, the current defense measures focus on replacing UDP.
-
The TLS (Cloudflare)
-
HTTP (Tencent Cloud, Ali Cloud)
-
HTTPS (Cloudflare, Google)
Three common alternatives are popular
-
DNS over TLS. This protocol transfers DNS content over TLS, similar to HTTPS and TLS.
-
DNS over HTTP. It is also possible to transmit DNS using HTTP. There is more support for this scheme among domestic manufacturers. The simplest implementation is to use a fixed IP address as a DNS server, and instead of UDP, HTTP requests are sent to this server to get the resolution results. However, it is often difficult to issue certificates to fixed IP addresses, so some vendors encrypt HTTP packets themselves to prevent these parsed results from being tampered with by middlemen.
-
DNS over HTTPS. Similar to the second point, the difference is that HTTPS is used. From what I’ve observed, Google and Cloudflare use domain names rather than fixed IP addresses, so you still have to resolve the DNS’s own domain name before you can actually query. This can lead to man-in-the-middle harassment again, forcing users to demote to plain UDP.
Unfortunately, none of these three more secure DNS queries can be used in the front end because browsers do not expose DNS interfaces. IOS and Android developers have the opportunity to use the technology to enhance, but need to write some code separately.
It is also a good idea to call the Ministry of Industry and Information Technology (12300) to complain.
HTTP hijacked
HTTP is a plaintext protocol. Any device on the intermediate link can tamper with the content, resulting in traffic hijacking.
Defense strategy
content security policy
CSP was originally a technical solution to fight against XSS. Its principle is to specify URL whitelist rules for each resource when HTML is loaded to prevent XSS from running and data sending out. But if you use the rules wisely, you can force all resources to go HTTPS, which reduces the possibility of traffic hijacking.
Subresource Integrity
SRI is a method for verifying resources. It reads the integrity attribute of the resource tag and compares the information summary value with the actual information summary value of the resource. If there is no match, the browser rejects the resource. In the case of a
SRI can be enabled by adding integrity to the link tag or script tag, for example:
<script
type="text/javascript"
src="//s.url.cn/xxx/aaa.js"
integrity="sha156-xxx sha384-yyy"
crossorigin="anonymous"
></script>
Copy the code
The integrity value is divided into two parts. The first part specifies the hash generation algorithm (SHA256, SHA384, and SHA512), and the second part is the actual hash encoded in Base64, separated by a short bar (-). The integrity value can contain multiple space-separated hashes, and as long as the file matches any one of the hashes, the resource can be verified and loaded. In the previous example, I used sha256 and SHA384 hash schemes.
Remark: What crossorigin=”anonymous” does is introduce cross-domain scripting, and in HTML5 there’s a way to get cross-domain scripting error messages, First, the server for cross-domain scripting must Allow the current domain name to get error messages through the Access-Control-allow-Origin header, and then the script tag for the current domain name must declare cross-domain support, that is, the Crossorigin attribute. Tags such as link and IMG support cross-domain scripting. If the above two conditions are not met, a try catch scheme can be used.
Script tags containing integrity attributes can be generated by using webpack’s html-webpack-plugin and webpack-subresource-integrity.
import SriPlugin from 'webpack-subresource-integrity';
const compiler = webpack({
output: {
crossOriginLoading: 'anonymous',},plugins: [
new SriPlugin({
hashFuncNames: ['sha256'.'sha384'].enabled: process.env.NODE_ENV === 'production',})]});Copy the code
What to do when script or link resource SRI fails?
A better way is to reload resources between static file servers when onerror is encountered via script onerror:
<script
type="text/javascript"
src="//11.url.cn/aaa.js"
integrity="sha256-xxx sha384-yyy"
crossorigin="anonymous"
onerror="loadScriptError.call(this, event)"
onsuccess="loadScriptSuccess"
></script>
Copy the code
To do this, inject the following code:
(function () {
function loadScriptError (event) {
/ / report.// Reload the js
return new Promise(function (resolve, reject) {
var script = document.createElement('script')
script.src = this.src.replace(/\/\/11.src.cn/.'https://x.y.z') // Replace the CDN address with the static file server address
script.onload = resolve
script.onerror = reject
script.crossOrigin = 'anonymous'
document.getElementsByTagName('head') [0].appendChild(script)
})
}
function loadScriptSuccess () {
/ / report. }window.loadScriptError = loadScriptError
window.loadScriptSuccess = loadScriptSuccess
})()
Copy the code
What is more painful is that the events in onError cannot distinguish the causes of errors, which may be the non-existence of resources, or the failure of SRI verification. Of course, the most frequent occurrence is request timeout. However, at present, there is no big problem with non-discrimination unless there is statistical requirement.
Inject the onError event
Of course, since the script tag in the project is packaged by webpack, we will use script-ext-html-webpack-plugin to inject onError and onSuccess events into it:
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
module.exports = {
/ /...
plugins: [
new HtmlWebpackPlugin(),
new SriPlugin({
hashFuncNames: ['sha256'.'sha384'],}).new ScriptExtHtmlWebpackPlugin({
custom: {
test: /\/*_[A-Za-z0-9]{8}.js/,
attribute: 'onerror'.value: 'loadScriptError.call(this, event)',}}),new ScriptExtHtmlWebpackPlugin({
custom: {
test: /\/*_[A-Za-z0-9]{8}.js/,
attribute: 'onsuccess'.value: 'loadScriptSuccess.call(this, event)',},}),],};Copy the code
The loadScriptError and loadScriptSuccess methods are then injected into THE HTML, using inline.
CDN hijacked
As mentioned above, script loading failure may be caused by a variety of reasons, so how to determine whether CDN hijacking occurred?
The method is to request the data again, compare the contents of the file twice (not all of course), and draw a conclusion if the contents are inconsistent.
function loadScript(url) {
return fetch(url)
.then(res= > {
if (res.ok) {
return res;
}
return Promise.reject(new Error());
})
.then(res= > {
return res.text();
})
.catch(e= > {
return ' ';
});
}
Copy the code
Compares whether the script loaded twice is the same
function checkScriptDiff(src, srcNew) {
return Promise.all([loadScript(src), loadScript(srcNew)])
.then(data= > {
var res1 = data[0].slice(0.1000);
var res2 = data[1].slice(0.1000);
if(!!!!! res1 && !! res2 && res1 ! == res2) {// CDN hijacking occurred
}
})
.catch(e= > {
// ...
});
}
Copy the code
Why only the first 1000 characters are compared here? Because CDN hijackers usually inject some code at the front of js files to achieve their purpose, injecting intermediate code requires AST parsing and costs a lot, so comparing all strings is meaningless. If you still have concerns, you can add the last n character comparison.
We actually will encrypt the data md5 if there is hijacking tampering, the server can detect