头图

a weird bug

Thank you very much Xiao Zhao for giving me feedback on this bug 🙌🙌

Test your Javascript basics before you start explaining. Just looking at the code, what do you think it will output? The answer will be revealed later.

 'Hello'.replace('ello', '#$&%')

In other words, one day I suddenly received an email, a classmate told me that my site was bombed, and I was so frightened that I suddenly rolled over from the bed - I felt that the charging cable was a bit strangling and I turned back again...

After a wave of detailed inquiries, I learned that it is my self-built blog site, which is the one I am currently writing an article on. It will display a part of the code at the bottom of the page on a certain page. like this:

现象

Feeling bad all of a sudden - the dead bug came back to attack me all of a sudden. .

This problem actually appeared before, but I fixed it later. Today it appeared again, and I quickly reproduced it, but I found that I had no problem with my own access. I finally found that it was a problem with the rendering script of my server. . So if you go directly to the site and browse the article, you won't encounter it. Most of the time I thought it was fixed. The way to reproduce is also very simple: you have to go directly to a certain blog post from a certain link to trigger it, which is very interesting! Basically, it can be explained that it is triggered due to data reasons.

Because my server-side rendering is written in Express, not a ready-made framework, there may be problems in some places and it is normal. After a wave of exploration, a block of code is located, and the debugging results are very strange. Roughly:

 // 我的页面模板
const template = fn();

// 渲染出来的页面样式
const css = fn();

// 当前访问页面所用到的 React state
const state = fn();

// 将所有内容由不同的锚点定位,替换到模板中去,每个锚点有且只有一个
const page = template
  .replace('css anchor', css)
  .replace('state anchor', state)

console.log(template.includes('state anchor'))
// true
console.log(page.includes('state anchor'))
// true
console.log(state.includes('state anchor'))
// false

Heck! Do the traces in the page still exist after being replaced? Then I added another test later:

 const page = template
  .replace('css anchor', css)
  .replace('state anchor', state)
  .replace('state anchor', 'f*** me')

console.log(template.includes('state anchor'))
// true
console.log(page.includes('state anchor'))
// false
console.log(state.includes('state anchor'))
// false

It's weird, I replaced it again and it was comfortable and gone. . Then I followed the position where the trace was replaced, and finally found it in this position in a certain piece of text:

 " Use <Space-E> to open explorer
" Using Coc-explorer
noremap <space>e :CocCommand explorer<CR>
" Close Coc-explorer if it is the only window
autocmd BufEnter * if (&ft == 'coc-explorer' && winnr("$") == 1) | q | endif

This is my previous article about Vim and Coc. Focus on this winnr("$") , because the page is escaped during rendering, the data obtained is actually &quot;$&quot; . That is, two quotation marks are replaced with &quot; now. And what I used above is replace to replace the content. And guess what in the replacement text of the replace method? $& represents the matching content itself! So my actual replacement would be: winnr(&quot;f*** mequot;) ...

Let's start explaining~

In fact, the replace function of strings in Javascript has a specific escape character (variable name) when the incoming parameter is a string. For example above, if you write '$&' then it will replace your search character in it. There are others like this:

 $$
是插入一个 "$"。

$&
是插入匹配的子串。

$`
是插入当前匹配的子串左边的内容。

$'
是插入当前匹配的子串右边的内容。

$n
假如第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,
那么插入第 n 个括号匹配的字符串。提示:索引是从 1 开始。如果不存在第 n 个分组,
那么将会把匹配到到内容替换为字面量。比如不存在第 3 个分组,就会用“$3”替换匹配到的内容。

$<Name>
这里 Name 是一个分组名称。如果在正则表达式中并不存在分组(或者没有匹配),
这个变量将被处理为空字符串。只有在支持命名分组捕获的浏览器中才能使用。

Of course, you can also pass the function in without passing the string. This is not expanded, you can go here for a closer look: MDN - String.prototype.replace()

Switching to the actual situation is because the anchor point of the state I insert is a script tag, so the content of Html is truncated. It's a bit similar to the principle of cross-site attack (XSS), so it's just a broken code block at the bottom of the page and the display of the text is normal.

It's easy to fix if you know what the problem is! Just write a replacement function that won't be escaped by any string.

You can think about how to write it yourself 🤣

Then there is the opening question, do you know what the answer is now?

 'Hello'.replace('ello', '#$&%')
// 'H#ello%'

Alright, that's it for today~


阿兵
7 声望2 粉丝