iT邦幫忙

1

再求助:具有潛在危險 Request.Form 的值已從用戶端 (Description="<!--是註解 ") 偵測到。的JS寫法

這篇是延續這裡:https://ithelp.ithome.com.tw/questions/10194939
在Submit之後,先將欄位處理,發現一個很奇怪的現象
我寫法如下

submit_data=(GodTalkForm.Description.value);
submit_data =submit_data
        .replace(/\&/g, '&amp;')
        .replace(/\"/g, '&quot;')
        .replace(/\'/g, '&#39;')
        .replace(/\</g, '&lt;')
        .replace(/\>/g, '&gt;')
	;
document.GodTalkForm.Description.innerText = submit_data;

欄位內的測試資料是:

<script>alert("BOO");</script>

寫入MS SQL資料庫之後是
& lt;script& gt;alert(& quot;BOO& quot;);& lt;/script& gt;
當然顯示時也是正常的,可能是瀏覽器自己轉換了,因為瀏覽器原始碼看見的是& l t ;,但顯示正確的小於符號

到這裡都還正常

然後啊然後啊,神奇的事情就發生了!!!
上線之後,有人輸入

<Abraham>亞伯拉罕

**又出現了
'/' 應用程式中發生伺服器錯誤。
具有潛在危險 Request.Form 的值已從用戶端 (Description="亞伯拉罕") 偵測到。

這個警告訊息
我不明白啊,為什麼整個alert那麼多符號都過濾了,怎麼可能發生一個小於就失敗的情況呀
抱頭/images/emoticon/emoticon02.gif
請問我submit有什麼問題?還是其他地方要修改?
我的系統是server2016 IIS,MSSQL,autoweb大約2010年左右買的,沒後續保固原廠不支援,但應該還是我JS的問題,又要求各位幫忙了/images/emoticon/emoticon67.gif

看更多先前的討論...收起先前的討論...
YoChen iT邦研究生 1 級 ‧ 2019-09-03 10:23:24 檢舉
請問您是Web Form還是MVC呢?
fillano iT邦超人 1 級 ‧ 2019-09-03 10:50:59 檢舉
你先用瀏覽器的開發工具看一下post到伺服器的資料是否符合你的預期。
josephine iT邦新手 4 級 ‧ 2019-09-03 10:56:17 檢舉
YoChen :
是web喔
josephine iT邦新手 4 級 ‧ 2019-09-03 10:59:49 檢舉
fillano
我從資料庫看,英數的小於大於會變成全形的小於大小
比如
<Abraham>亞伯拉罕變成中文全形的
<Abraham>亞伯拉罕
這樣
ccutmis iT邦高手 2 級 ‧ 2019-09-03 11:02:37 檢舉
autoweb能自己改寫asp函式嗎 能的話可以試試這個思路
1.把submit_data裡的 小於符號 用 '{{{{{' 取代
(例如原本是<a 會變成 {{{{{a )
2.寫入MSSQL後,從DBMS裡面看存入欄位內容是否為'{{{{{a'
3.在你讀取欄位內容的asp頁面寫函式把字串'{{{{{'用'<'取代
我沒有iis可以試,底下的範例只是邏輯供您參考:
Function restore_left_angle_brackets(arg)
 restore_left_angle_brackets=(Replace(arg,"{{{{{","<"))
End Function

Response.Write((restore_left_angle_brackets("{{{{{abc>"))
'把'{{{{{abc>'變成'<abc>'
YoChen iT邦研究生 1 級 ‧ 2019-09-03 11:10:32 檢舉
如果是WebForm您參考dragonH大的解法比較好
josephine iT邦新手 4 級 ‧ 2019-09-03 11:42:09 檢舉
ccutmis
試過了沒用
問題是IIS或.net只要submit之後發現有<符號加任何一個字母或驚嘆號就會出現這個警告訊息,如果是數字或中文就沒問題,小於跟字母之間插空格也沒問題
可偏偏長老們都已經非常習慣貼上來的東西就是用方括號加英文的形式.....
ccutmis iT邦高手 2 級 ‧ 2019-09-03 12:28:29 檢舉
@josephine 我有在底下回文了,希望有幫助!
josephine iT邦新手 4 級 ‧ 2019-09-05 10:34:01 檢舉
謝謝大家幫忙
星期二突然不能留言,IT邦說我留言次數超過上限....第一次知道這種事
昨天急診,今天我會再試試看大家的方法
再次謝謝 上帝愛你們 啾咪^o<
josephine iT邦新手 4 級 ‧ 2019-09-06 13:36:17 檢舉
總覺得這應該是實作時很多人都會遇到的問題,而且是很古老的問題....托腮嘆@@
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
3
dragonH
iT邦超人 5 級 ‧ 2019-09-03 10:25:31
最佳解答

codepen

要不要試試我上一篇說的

用 escape 呢/images/emoticon/emoticon11.gif

看更多先前的回應...收起先前的回應...
josephine iT邦新手 4 級 ‧ 2019-09-03 10:54:41 檢舉

escape剛才找了一下資料,不懂,那不是針對URL編碼的嗎?要怎麼用在欄位?

fillano iT邦超人 1 級 ‧ 2019-09-03 11:01:03 檢舉
alert(escape('<Abraham>亞伯拉罕'));

你看看會跑出什麼,其實你用的replace也是類似效果。並沒有規定誰只能用在哪裡,只要能達到你要的效果就可以用。

fillano iT邦超人 1 級 ‧ 2019-09-03 11:07:52 檢舉

另外,post資料時,用的格式通常是url encoded。也就是在向伺服器送request的時候,Content-Type檔頭是application/x-www-form-urlencoded,然後http request body內容是像這樣:

field1=abcde&id=3&codename=fillano&page=4
dragonH iT邦超人 5 級 ‧ 2019-09-03 11:20:25 檢舉

/images/emoticon/emoticon32.gif

josephine iT邦新手 4 級 ‧ 2019-09-03 11:27:33 檢舉

這樣

submit_data=(GodTalkForm.Description.value);
submit_data =escape(submit_data);
document.GodTalkForm.Description.innerText = submit_data;

和這樣

submit_data=(GodTalkForm.Description.value);
document.GodTalkForm.Description.innerText = escape(submit_data);

亞伯拉罕就一樣的錯誤訊息 ..../images/emoticon/emoticon17.gif
alert BOO也不正常了

dragonH iT邦超人 5 級 ‧ 2019-09-03 11:37:43 檢舉

你轉完的東西是長怎樣呢

印出來看看

YoChen iT邦研究生 1 級 ‧ 2019-09-03 11:42:16 檢舉

你是不是應該把值存回value裡?

josephine iT邦新手 4 級 ‧ 2019-09-03 11:47:46 檢舉

沒有轉換後的東西,全部 都錯誤,也沒寫進資料庫

josephine iT邦新手 4 級 ‧ 2019-09-03 11:49:15 檢舉

document.GodTalkForm.Description.innerText不就是寫回去了嗎?

josephine iT邦新手 4 級 ‧ 2019-09-03 11:51:57 檢舉
submit_data=(GodTalkForm.Description.value);

document.GodTalkForm.Description.innerText = escape(submit_data);

我是這樣 寫的

YoChen iT邦研究生 1 級 ‧ 2019-09-03 12:00:14 檢舉

改成這樣呢

document.GodTalkForm.Description.value = escape(submit_data);
dragonH iT邦超人 5 級 ‧ 2019-09-03 12:10:08 檢舉

codepen

innerText 跟 value 的差別

打開 browser console 看 network 送出的東西

https://ithelp.ithome.com.tw/upload/images/20190903/20117259LrgxDsU5sm.png

再看 html

https://ithelp.ithome.com.tw/upload/images/20190903/20117259xDpr7YTzjq.png

josephine iT邦新手 4 級 ‧ 2019-09-03 14:15:42 檢舉

將innerText改成value總算成功了,但新的問題是,如此儲存的資料 都是編碼後的,像這樣https://ithelp.ithome.com.tw/upload/images/20190903/20092581RrCLYuPcgm.png
這樣就沒辦法查詢了
不好意思,再請教我要怎麼後處理讓資料以明碼方式儲存在微軟SQL?
看是在js或sql後處理做都好

dragonH iT邦超人 5 級 ‧ 2019-09-03 14:32:16 檢舉

josephine

codepen

給你參考

以後有新的要過濾的符號

就往 myTargets 加 就好

const myReplace = (input) => {
  let myInput = input;
  const myTargets = ['<', '>', '&', '"', "'"];
  myTargets.forEach((myTarget) => {
    const regexp = new RegExp(myTarget, 'g');
    myInput = myInput.replace(regexp, escape(myTarget));
  });
  return myInput;
}
josephine iT邦新手 4 級 ‧ 2019-09-06 13:08:26 檢舉

謝謝 dragonH
不過9/3 14:32這個範例,我不知道要怎麼改成可用的耶
照抄似乎不能動作,那是JS的Function嗎?

josephine iT邦新手 4 級 ‧ 2019-09-06 13:14:52 檢舉

我的JS不認識 const ?/images/emoticon/emoticon06.gif

josephine iT邦新手 4 級 ‧ 2019-09-06 13:30:29 檢舉

這篇的解答

原先我參考很多網路資料 ,基本上都跟這篇提供相似的範例

這幾天,我用最笨的方式,一個一個的符號都測試,發現一次只測一個符號就沒問題,混合使用,就會難預期的發生錯誤 。
後來,我看到這篇

突然發現,怎麼每個符號的HTML Entity都是用Name去比對轉換,那個不合作的單引號偏偏是用Number去做,一時個性使然把

.replace(/'/g, '&#39;')

改成

.replace(/\'/gim, '&apos;')

再經過很多測試,發現 都沒再發生錯誤
我找不到這方面的解譯資料,只能猜測,也許是HTML Entity不能混用Name與Number,那網路範例不應該是大家千鎚百煉的嗎?大概是js的版本又修正了吧
儲存的資料也是如預期
https://ithelp.ithome.com.tw/upload/images/20190906/20092581SFBE7kM8Gl.png
至於查詢時,一樣輸入

<Abraham>亞伯拉罕

用SQLProfiler追蹤,會用HTML Entity去比對,也不用特別改寫SQL了。
謝謝大家幫忙 /images/emoticon/emoticon41.gif

josephine iT邦新手 4 級 ‧ 2019-09-06 13:31:33 檢舉

留言不能貼圖,所以放在這邊

dragonH iT邦超人 5 級 ‧ 2019-09-06 15:01:13 檢舉

不認識 const

應該是遇到 ES6 的問題

.replace(/'/gim, ''')

可是你這樣

變成所有符號都要先寫好

還不如用 escape 幫你轉

YoChen iT邦研究生 1 級 ‧ 2019-09-06 15:06:46 檢舉

josephine
replace的缺點在於說,每當您多一種特殊字元需要排除,就必須修改程式碼,這樣其實滿麻煩的~XDDD
escape就是能避免這樣的事情發生~
另外回答您有關Server端的做法,通常我們在前端通過驗證過後的escape字串,到Server端以後會透過

string valueUsedInSQL = Regex.Unescape(escapeStringFormRequest);

來將字串還原,最後才將他塞進SQL Parameter,這樣不但能確保資料格式正確(不會變成HTML Entity),也方便您在DB更好的去下DML~
以上供您參考~

1
YoChen
iT邦研究生 1 級 ‧ 2019-09-03 11:13:42

WebForm控制項搭配escape的應用,您可以參考這篇~
https://stackoverflow.com/questions/11673107/how-do-i-allow-html-tags-to-be-submitted-in-a-textbox-in-asp-net
基本上的解法跟dragonH大提供的方法是一樣的~

josephine iT邦新手 4 級 ‧ 2019-09-06 13:10:05 檢舉

謝謝YoChen
不過編碼後的資料無法查詢,幸好現在已經解決,就是不要用escape,我犯了一個沒經驗的錯誤,等一下公佈在留言那邊

1
ccutmis
iT邦高手 2 級 ‧ 2019-09-03 12:27:47

給樓主參考,感覺是一個古老的問題...
http://www.blueshop.com.tw/board/FUM20041006161839LRJ/BRD200305271036247G8.html
2003年的問題,2012年還有人回覆 (我的建議方案是參考該文第12樓的回文)

還有另一種方法:
先用「別的符號」來代替,只要不是HTML的Tag,其它的符號只要你自己能夠辨認就好。
存入資料庫後,將來要讀取,再用程式去判斷、去解碼即可!

樓主原本字串取代的部份是這樣寫

submit_data=(GodTalkForm.Description.value);
submit_data =submit_data
        .replace(/\&/g, '&amp;')
        .replace(/\"/g, '&quot;')
        .replace(/\'/g, '&#39;')
        .replace(/\</g, '&lt;')
        .replace(/\>/g, '&gt;')
	;
;
document.GodTalkForm.Description.innerText = submit_data;

改成

submit_data=(GodTalkForm.Description.value);
submit_data =submit_data
        .replace(/\&/g, '&amp;')
        .replace(/\"/g, '&quot;')
        .replace(/\'/g, '&#39;')
        .replace(/\</g, '{{{{{')
        .replace(/\>/g, '}}}}}')
	;
document.GodTalkForm.Description.value=submit_data;

存檔修改並測試網頁寫入資料庫,如果沒有再出現錯誤訊息,
再進資料庫看看你存進去的值是否把左右小括號替換成"{{{{{{"及"}}}}}",
若有則表示成功一半了。
最後在你顯示資料的頁面寫個函式來處理把"{{{{{{"及"}}}}}"還原回原本的左右小括號
例如:

<%
'註:這是ASP的函式範例,這邊假設樓主的網頁能跑ASP程式
Function restore_special_chars(arg)
  arg=Replace(arg,"&","&")
  arg=Replace(arg,""",chr(34))
  arg=Replace(arg,"'","'")
  arg=Replace(arg,"{{{{{","<")
  arg=Replace(arg,"}}}}}",">")
  restore_left_angle_brackets=arg
End Function
'用法範例: 
Response.Write(restore_special_chars('{{{{{div id="Hello&World"}}}}}'))
'返回字串'<div id="Hello&World">'
%>

上列的Function沒有實際測試過,只是提供思路給您參考。

看更多先前的回應...收起先前的回應...
josephine iT邦新手 4 級 ‧ 2019-09-03 14:18:41 檢舉

謝謝ccutmis
但不管將小於符號換成任何字串都是失敗的
不過剛才發現我如果將innerText改成value就能成功避開.net的安全過濾,問題是儲存的資料全是編碼後的

fillano iT邦超人 1 級 ‧ 2019-09-03 15:39:54 檢舉

...submit的資料應該是放在value,不是innerText吧?

儲存的資料是怎樣編碼?

ccutmis iT邦高手 2 級 ‧ 2019-09-03 15:48:54 檢舉

我覺得你的問題可能是出在表單送出資料前不知哪邊沒寫好,
我弄了一個簡單的範例把它丟到網路上,
沒有你說的這種問題...
demo網址:
http://www.web3d.url.tw/php20190903/index.htm

index.htm source:

<html>
<head><meta charset="utf-8" /></head>
<body>
<form method="post" action="test2.php" name="GodTalkForm" onsubmit='return checkForm();'>
<textarea id="Description" name="Description" style="width:99vw;height:20vh;">
<!doctype html>
<!-- this is a test -->
<a href="ha.htm" title="haha" >hahaha</a>
<Abraham>亞伯拉罕</Abraham>
</textarea>
<input type="submit" name="submit" value="submit" />
</form>

<script>
function checkForm(){
	submit_data=(GodTalkForm.Description.value);
	console.log('原始字串:'+submit_data);
	submit_data =submit_data
		.replace(/\"/g, '{LLLLL}').replace(/\'/g, '{JJJJJ}')
		.replace(/\</g, '{{{{{').replace(/\>/g, '}}}}}');
	console.log('取代後字串:'+submit_data);
	document.GodTalkForm.Description.value = submit_data;
	return true;
}
</script>
</body>
</html>

index.htm按送出後,會把修改過字串的表單內容傳送到test2.php
(我沒asp環境可以測只好用php跑給你看,不過邏輯思路是一樣的)
test2.php source:

<!doctype html><html><head><meta charset='utf-8' /></head><body>
<?php
function restore_special_chars($arg){
	$arg=str_replace('{LLLLL}','"',$arg);
	$arg=str_replace('{JJJJJ}','\'',$arg);
	$arg=str_replace('{{{{{','<',$arg);
	$arg=str_replace('}}}}}','>',$arg);
	return $arg;
}

echo '從test1.htm傳過來的原始字串:<br/>';
echo $_POST['Description'];
echo '<hr/>用自訂函式把原始字串裡的特殊符號恢復(請檢視原始碼較清楚差異):<br/>';
echo restore_special_chars($_POST['Description']);
?>
</body></html>

理論上這寫法能避掉你說的送出表單時Description內容會有小括號加英文字的情況,繞過IIS報錯,然後存入資料庫,這部份沒問題,再來處理把資料撈出來之後要怎樣把小括號們復原。

ps.另外儘量不要用<跟>或&#xxx;來作為替代符號,它們其實就是html實體,為了避免跟其它的原始碼打架我是用"{{{{{"跟"}}}}}"來作為小括號的替代符號,如果這部份確定有替代但還是出錯可能要看看是不是有其它同樣需要過濾的符號,例如:!,&,@,+,-等等,我這邊沒有autoweb跟iis可以測,只能猜了。
josephine iT邦新手 4 級 ‧ 2019-09-06 13:12:00 檢舉

謝謝ccutmis
您真好,還特別 做了一個實例網頁
不過我套用在我電腦上,'{LLLLL}'這種格式的反而無法執行,不過現在還是回到原來的辦法解決了,留言那邊有公佈,謝謝您

josephine iT邦新手 4 級 ‧ 2019-09-06 13:34:13 檢舉

後來我又測了一下,您的公式是能用的,只是/g要改/gim,因為我測試資料是多行,只有/g的話,後面行的符號沒轉換就警告了

1
純真的人
iT邦大師 1 級 ‧ 2019-09-03 17:06:35

那個...跟JS無關..
他是另外驗證資料原始碼是否有含指定符號【具有潛在危險】
你在怎麼轉都是無解的~
除非你一開始submite的資料就是編碼過的~否則一律都擋..

josephine iT邦新手 4 級 ‧ 2019-09-06 13:12:37 檢舉

謝謝 純真的人
是的,所以這篇一直在submit處理

1
萊恩
iT邦新手 5 級 ‧ 2019-09-04 09:45:16

你送出去的成對小括號之所以會被判定為具潛在危險
是因為任何一個人可以把 javascript 在你的頁面上直接執行 (XSS)

<script>
    alert('123'); // 這段有可能被換成任何危險的 script
<script>

這樣是一件蠻可怕的事情,因為任何一個人都可以寫一段惡意的 script
把 cookie 這類的資訊往遠端主機送

所以噴出這個錯誤的主要意義還是希望你可以 編碼過後 再進行儲存
那如同你留下的回應,編碼的資料不知道如何做 SQL 查詢
那麼你應該是把符號也一起編碼之後變成查詢的字串才對

大概像下面這樣(沒意外的話應該還是可以搜尋就是了,樓主可能要試試看)

SELECT *
FROM SomeTable s
WHERE s.Description LIKE '%&lt;script&gt;%' 
-- &lt;script&gt; 這是從外面先編碼才傳進來的
josephine iT邦新手 4 級 ‧ 2019-09-06 13:14:15 檢舉

謝謝萊恩
我找到解決辦法了,在submit那邊有個地方改一下,新增或查詢都正常,而且資料庫也是明碼可讀,又不會有XSS的問題

我要發表回答

立即登入回答