這篇是延續這裡:https://ithelp.ithome.com.tw/questions/10194939
在Submit之後,先將欄位處理,發現一個很奇怪的現象
我寫法如下
submit_data=(GodTalkForm.Description.value);
submit_data =submit_data
.replace(/\&/g, '&')
.replace(/\"/g, '"')
.replace(/\'/g, ''')
.replace(/\</g, '<')
.replace(/\>/g, '>')
;
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那麼多符號都過濾了,怎麼可能發生一個小於就失敗的情況呀
抱頭
請問我submit有什麼問題?還是其他地方要修改?
我的系統是server2016 IIS,MSSQL,autoweb大約2010年左右買的,沒後續保固原廠不支援,但應該還是我JS的問題,又要求各位幫忙了
escape剛才找了一下資料,不懂,那不是針對URL編碼的嗎?要怎麼用在欄位?
alert(escape('<Abraham>亞伯拉罕'));
你看看會跑出什麼,其實你用的replace也是類似效果。並沒有規定誰只能用在哪裡,只要能達到你要的效果就可以用。
另外,post資料時,用的格式通常是url encoded。也就是在向伺服器送request的時候,Content-Type檔頭是application/x-www-form-urlencoded
,然後http request body內容是像這樣:
field1=abcde&id=3&codename=fillano&page=4
這樣
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);
亞伯拉罕就一樣的錯誤訊息 ....
alert BOO也不正常了
你轉完的東西是長怎樣呢
印出來看看
你是不是應該把值存回value裡?
沒有轉換後的東西,全部 都錯誤,也沒寫進資料庫
document.GodTalkForm.Description.innerText不就是寫回去了嗎?
submit_data=(GodTalkForm.Description.value);
document.GodTalkForm.Description.innerText = escape(submit_data);
我是這樣 寫的
改成這樣呢
document.GodTalkForm.Description.value = escape(submit_data);
將innerText改成value總算成功了,但新的問題是,如此儲存的資料 都是編碼後的,像這樣
這樣就沒辦法查詢了
不好意思,再請教我要怎麼後處理讓資料以明碼方式儲存在微軟SQL?
看是在js或sql後處理做都好
給你參考
以後有新的要過濾的符號
就往 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;
}
謝謝 dragonH
不過9/3 14:32這個範例,我不知道要怎麼改成可用的耶
照抄似乎不能動作,那是JS的Function嗎?
我的JS不認識 const ?
這篇的解答
原先我參考很多網路資料 ,基本上都跟這篇提供相似的範例
這幾天,我用最笨的方式,一個一個的符號都測試,發現一次只測一個符號就沒問題,混合使用,就會難預期的發生錯誤 。
後來,我看到這篇
突然發現,怎麼每個符號的HTML Entity都是用Name去比對轉換,那個不合作的單引號偏偏是用Number去做,一時個性使然把
.replace(/'/g, ''')
改成
.replace(/\'/gim, ''')
再經過很多測試,發現 都沒再發生錯誤
我找不到這方面的解譯資料,只能猜測,也許是HTML Entity不能混用Name與Number,那網路範例不應該是大家千鎚百煉的嗎?大概是js的版本又修正了吧
儲存的資料也是如預期
至於查詢時,一樣輸入
<Abraham>亞伯拉罕
用SQLProfiler追蹤,會用HTML Entity去比對,也不用特別改寫SQL了。
謝謝大家幫忙
留言不能貼圖,所以放在這邊
不認識 const
應該是遇到 ES6 的問題
.replace(/'/gim, ''')
可是你這樣
變成所有符號都要先寫好
還不如用 escape 幫你轉
josephine
replace的缺點在於說,每當您多一種特殊字元需要排除,就必須修改程式碼,這樣其實滿麻煩的~XDDD
escape就是能避免這樣的事情發生~
另外回答您有關Server端的做法,通常我們在前端通過驗證過後的escape字串,到Server端以後會透過
string valueUsedInSQL = Regex.Unescape(escapeStringFormRequest);
來將字串還原,最後才將他塞進SQL Parameter,這樣不但能確保資料格式正確(不會變成HTML Entity),也方便您在DB更好的去下DML~
以上供您參考~
WebForm控制項搭配escape的應用,您可以參考這篇~
https://stackoverflow.com/questions/11673107/how-do-i-allow-html-tags-to-be-submitted-in-a-textbox-in-asp-net
基本上的解法跟dragonH大提供的方法是一樣的~
給樓主參考,感覺是一個古老的問題...
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, '&')
.replace(/\"/g, '"')
.replace(/\'/g, ''')
.replace(/\</g, '<')
.replace(/\>/g, '>')
;
;
document.GodTalkForm.Description.innerText = submit_data;
改成
submit_data=(GodTalkForm.Description.value);
submit_data =submit_data
.replace(/\&/g, '&')
.replace(/\"/g, '"')
.replace(/\'/g, ''')
.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沒有實際測試過,只是提供思路給您參考。
謝謝ccutmis
但不管將小於符號換成任何字串都是失敗的
不過剛才發現我如果將innerText改成value就能成功避開.net的安全過濾,問題是儲存的資料全是編碼後的
...submit的資料應該是放在value,不是innerText吧?
儲存的資料是怎樣編碼?
我覺得你的問題可能是出在表單送出資料前不知哪邊沒寫好,
我弄了一個簡單的範例把它丟到網路上,
沒有你說的這種問題...
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可以測,只能猜了。
謝謝ccutmis
您真好,還特別 做了一個實例網頁
不過我套用在我電腦上,'{LLLLL}'這種格式的反而無法執行,不過現在還是回到原來的辦法解決了,留言那邊有公佈,謝謝您
後來我又測了一下,您的公式是能用的,只是/g要改/gim,因為我測試資料是多行,只有/g的話,後面行的符號沒轉換就警告了
那個...跟JS無關..
他是另外驗證資料原始碼是否有含指定符號【具有潛在危險】
你在怎麼轉都是無解的~
除非你一開始submite的資料就是編碼過的~否則一律都擋..
你送出去的成對小括號之所以會被判定為具潛在危險
是因為任何一個人可以把 javascript 在你的頁面上直接執行 (XSS)
<script>
alert('123'); // 這段有可能被換成任何危險的 script
<script>
這樣是一件蠻可怕的事情,因為任何一個人都可以寫一段惡意的 script
把 cookie 這類的資訊往遠端主機送
所以噴出這個錯誤的主要意義還是希望你可以 編碼過後
再進行儲存
那如同你留下的回應,編碼的資料不知道如何做 SQL 查詢
那麼你應該是把符號也一起編碼之後變成查詢的字串才對
大概像下面這樣(沒意外的話應該還是可以搜尋就是了,樓主可能要試試看)
SELECT *
FROM SomeTable s
WHERE s.Description LIKE '%<script>%'
-- <script> 這是從外面先編碼才傳進來的