顯示具有 網頁設計 標籤的文章。 顯示所有文章
顯示具有 網頁設計 標籤的文章。 顯示所有文章

2021年8月29日 星期日

網站管理員搞烏龍

這是發生在國內某家高級中學全球資訊網的低級錯誤,已通報ZeroDay

是為了節省經費或者便宜行事?該網站在同一部伺服器上掛載兩套Web服務,一套用Apache+PHP,另一套是IIS+ASP,當然,這種作法大有人在,架構本身並不是什麼問題,問題出在網站的設定上!

基於職業道德,不便提供此網站的網址及細部資訊

該校首頁(PHP)利用iframe內嵌另一組新聞管理系統(ASP),由於兩個服務不能共用相同PORT,因此,首頁用PORT 80,新聞管理用PORT 8080,這樣分配很合理。不過,可能是PHP比較早建置,沒有考慮到會和ASP共用伺服器,所以將ASP網頁被當成一般文字檔。
依照正常操作,瀏覽此網站並不會發現異樣,亦即,瀏覽www.XXXX.edu.tw會開啟全球資訊網首頁,首頁中間就是內嵌的新聞管理系統。
點擊新聞管理系統的「登入」鈕,會彈出登入畫面(見上圖),注意登入畫面上的URL,它是走PORT 8080(www.XXXX.edu.tw:8080/admin.asp),如果瀏覽此網址,但將8080移除,會神奇地看到admin.asp的原始碼

從洩漏的原始碼可看出後端使用MS ACCESS資料庫及其路徑,只要給予正確路徑,便能下載資料庫檔,等於把整個資料庫都拿走了!

至於怎麼修正這個錯誤呢?最簡單的作法就是不要將ASP網頁和PHP放在同一個根目錄下,只要移動ASP目錄,在IIS重新設定虛擬目錄,就能避免PHP存取ASP的資源。
有管網站的朋友,請檢查看看,是否也犯下這般烏龍失誤!

2021年2月21日 星期日

又是Cookie惹的禍!Cookie裡的SQL Injection

 前一篇分享破解密碼」的經驗提到,開發人員將密碼編碼後記錄到Cookie裡,這一篇則是將資料庫的SQL語句記錄到Cookie裡,只要竄改Cookie裡的SQL語句,就能命令資料庫執行其他動作。

國內某地圖查詢服務網,當使用者輸入查詢資料後,會將完整的SQL語句記錄在Cookie的QuerySQL欄位中,使用者跳到下一資料頁或其他資料頁時,QuerySQL內容會傳回伺服器,而且伺服器直接以此SQL語句再次執行查詢,這讓駭客有了注入SQL命令的機會。

筆者曾試者利用SQLMAP去測試此進入點,但一直無法得到有效的回應,如果有同好知道如何利用SQLMAP直接攻擊SQL語句,尚請不吝指教!

基於職業道德,不便提供此服務網站的網址及細部資訊

首先,直接點擊查詢頁上的「顯示全部」鈕(圖1),可以得到各單位的清單,檢視清單頁的回應標頭之Cookie,可看到查詢的SQL語句(圖2)。

圖1:地圖查詢頁
圖2:查詢後,在cookei記錄SQL語句

為了重複測試,從換頁清單找出瀏覽網址(圖3),每次變更QuerySQL內容後,就瀏覽前述網址,讓資料庫伺服器執行QuerySQL所指定的SQL語句。

圖3:找出直接瀏覽的網址

為測試修改後的QuerySQL是否會交由後端執行,將SQL的條件移除(Where及之後的文字,如圖4),再重新瀏覽,此時系統真的回傳1839 頁(如圖5原本只有1頁),至此確認Cookie的QuerySQL存在SQL injection漏洞。

圖4:修改Cookie裡的QuerySQL的語句
圖5:從回傳的結果證實QuerySQL存在SQL Injection漏洞

再苦口婆心一次 若需要在session之間交換資料,請使用後端的session變數記錄欲交換的內容,千萬不要使用Cookie或頁面上的隱藏欄位,面對駭客,Cookie及隱藏欄位絲毫不具防護能力!

分享「破解密碼」的經驗

提醒程式開發人員 許多文章及書籍都告戒「密碼應經雜湊(hash)或『經驗證』的強加密演算法處理後再保存

某券商的網路下單系統,在登入後或變更密碼時,會將此密碼編碼並紀錄在Cookie裡,本文將說明如何破解從此Cookie內容而得到明文密碼。基於職業道德,不便提供此下單系統的網址及細部資訊

每次變更密碼後,檢視回應(response)的標頭(header)發現LoginPWD欄位值的長度是4的倍數(圖1),且字元符合BASE64編碼形式,猜測密碼是利用BASE64編碼後再記錄到Cookie,但是解碼LoginPWD的值卻得到亂碼(圖2),而非原來的密碼明文,推測「執行BASE64編碼前,密碼應該還進行其他編碼處理」。既然使用BASE64 to Text得到亂碼,只好改用BASE64 to Hex來觀查解碼後的內容(圖3)。

圖1:檢視回應內容的標頭資訊

 
圖2:直接解碼只得到亂碼
圖3:使用BASE64 to Hex查看解碼後的結果

要破解密碼,當然不會只使用一組資訊,下表是筆者以不同的密碼得出下單系統回傳的LoginPWD值,並和該密碼的BASE64編碼進行比較。

NO 密碼 直接BASE64編碼 密碼的Hex LoginPWD 解碼成Hex
1 AaBbCcDdE012 QWFCYkNjRGRFMDEy 416142624363446445303132 AZiE4EEKG79Npb05nw== 019884E0410A1BBF4DA5BD399F
2 AaBbCcdDe012 QWFCYkNjZERlMDEy 416142624363644465303132 AZiE4EEKO59tpb05nw== 019884E0410A3B9F6DA5BD399F
3 ABC123456789 QUJDMTIzNDU2Nzg5 414243313233343536373839 AbuFszBaa+4+orQynw== 01BB85B3305A6BEE3EA2B4329F
4 abc123456789 YWJjMTIzNDU2Nzg5 616263313233343536373839 IZulszBaa+4+orQynw== 219BA5B3305A6BEE3EA2B4329F
5 ABC123 QUJDMTIz 414243313233 AbuFszBaXw== 01BB85B3305A5F
6 abc123 YWJjMTIz 616263313233 IZulszBaXw== 219BA5B3305A5F

從上表可以找出幾個現象

  1. 當密碼長度不一樣時,LoginPWD的長度也不一樣,但仍維持4的倍數
  2. LoginPWD的長度都比直接BASE64編碼多出4個字元,如上表LowinPWD欄的粗藍字。
  3. 由於筆者測試的密碼都是3的倍數,而LoginPWD出多的4字元之後兩碼皆為==,依照BASE64的規則,代表有2個填充字元,推測下單系統會先在原密碼之後附加1字元再執行編碼。
  4. 比對各組密碼,相同位置相同字元,對應的LoginPWD內容也相同,如項次3及5紅字部分。

開始思考開發者可能使用的編碼方式

  1. 是不是使用對照表轉換BASE64的編碼字元?
    但從上表項次1或2的黃底字看到kN都對應到E,顯然不合理。
  2. 是不是使用特定KEY進行轉碼?
    試著將「密碼的Hex」與「解碼成Hex」的值進行XOR運算(「解碼成Hex」的最後一碼是附加的,故先捨棄),結果如下表的「XOR結果」欄
NO 密碼 密碼的Hex 解碼成Hex XOR結果
1 AaBbCcDdE012 416142624363446445303132 019884E0410A1BBF4DA5BD399F 40F9C68202695FDB08958C0B
2 AaBbCcdDe012 416142624363644465303132 019884E0410A3B9F6DA5BD399F 40F9C68202695FDB08958C0B
3 ABC123456789 414243313233343536373839 01BB85B3305A6BEE3EA2B4329F 40F9C68202695FDB08958C0B
4 abc123456789 616263313233343536373839 219BA5B3305A6BEE3EA2B4329F 40F9C68202695FDB08958C0B
5 ABC123 414243313233 01BB85B3305A5F 40F9C6820269
6 abc123 616263313233 219BA5B3305A5F 40F9C6820269

從上表的「XOR結果」得到如下結論

  1. 從項次1到6的XOR結果,可知下單系統會逐字元進行XOR處理。
  2. 由項次5多出來的「5F」,與項次4同一位置的KEY相同,得知下單系統附加的字元是ASCII的NUL字元(十六進制碼 00)。

目前解得35碼的XOR Key值是「40F9C68202695FDB08958C0B9F74F518BC6361D42F22998F31B2895B67BF64AA505D528E」,亦即「0x40,0xF9,0xC6,0x82,0x02,0x69,0x5F,0xDB,0x08,0x95,0x8C,0x0B,0x9F,0x74,0xF5,0x18,0xBC,0x63,0x61,0xD4,0x2F,0x22,0x99,0x8F,0x31,0xB2,0x89,0x5B,0x67,0xBF,0x64,0xAA,0x50,0x5D,0x52,0x8E」

知道XOR的Key值後,就能對任意LoginPWD進行解碼,步驟如下:

  1. 先將LoginPWD進行BASE64 to Hex解碼,得到十六進制結果,以HEX表示。
  2. HEX的最右邊的Byte捨棄,因它是附加的字元NUL,無關緊要。以HEX2表示。
  3. 從XOR Key的左邊取出和HEX2等長的資料,以KEY2表示。
  4. HEX2KEY2進行XOR
  5. 將得到的十六進制值轉成ASCII即得到密碼明文。

就以「LoginPWD: E62TszBaa+4+orQynw==」為例:

  1. 先將「E62TszBaa+4+orQynw==」進行BASE64 to Hex解碼,得到「13AD93B3305A6BEE3EA2B4329F」。
  2. 將「13AD93B3305A6BEE3EA2B4329F」最右邊的Byte(即9F)捨棄,剩12Byte。
  3. 從XOR Key的左邊取出12Byte,即「40F9C68202695FDB08958C0B」。
  4. 將「13AD93B3305A6BEE3EA2B432」與「40F9C68202695FDB08958C0B」進行XOR即得「535455313233343536373839」。
  5. 將「535455313233343536373839轉成ASCII,得到密碼明文「STU123456789」。

使用的線上工具如下

BASE64 編碼/解碼https://base64.guru/converter/decode/hex

XOR 計算器http://xor.pw/

ASCII/HEX轉換https://www.rapidtables.com/convert/number/hex-to-ascii.html

2020年11月7日 星期六

HITCON 2020 { IoT Hacking 101 }議程之 LV2題目的另類解法

今年的Hitcon 2020第一天Jimmy Liu老師主講「IoT Hacking 101」,主要是實作基礎的物聯網設備滲透測試!有關上課素材可從「https://github.com/DrmnSamoLiu/Hitcon-iot101」下載,上課簡報請參考素材包裡的DVIPcam_hitcon.pdf,在此假設您已事先閱讀並瞭此份簡報的內容。

參加此議題的同事於會後分享學習心得,而筆者事後練習時,又發現LV2(簡報22頁)有另一條啟用Telnet及FTP服務的途徑,借此做個筆記。

此題的網路攝影機預設只開啟端口443、554、8000,我們要想辦法辦啟動這台設備上的Telnet及FTP服務,即開啟端口23及21。

依照簡報內容,由於使用者未變更預設密碼,駭客可由使用手冊得知兩組登入帳密:「root / root」及「user / DVIPcam」,實際上,root的密碼已變更,無法直接以管理員身分登入管理界面,但user的密碼則未變更,駭客能夠經由提權而取得管理員權限,在瀏覽「System Configuration」頁面時啟用Telnet及FTP服務(簡報28頁)。好了,前述的滲透手法,簡報裡已寫得很清楚,這裡不再贅述。

但~~如果連user的預設密碼也被修改,有沒有「不需要網站的帳密就能開啟Telnet服務」的方法?這篇的手法就是了!

一、為了分析網站的原始碼,先從登入頁下載此設備的韌體更新檔(firmware.bin)。

二、利用7-zip開啟 firmware.bin,檢查 www/cgi-bin/ 目錄,注意readcookie.cgiConfig.cgiConfigsubmit.cgi這三個檔案。

三、檢查readcookie.cgi,發現呼叫此CGI時不會檢查是否已登入,且會將HTTP_COOKIE寫到/var/Allowed_SessionID,而Allowed_SessionID是判斷使用者有沒有登入的依據。我們就是利用此漏洞。

 四、檢視Config.cgi,發現它會載入 /var/web/Config.html,所以再檢視此網頁,發現它是用來設定FTP及Telnet開關,Submit的內容是Telnet=on/off&FTP=on/off,提交對象是「/cgi-bin/Configsubmit.cgi

 五、再檢視「Configsubmit.cgi」,發現此cgi並不會檢查權限,只要有session就可以成立。(剛剛的readcookie.cgi已可建立session)

 

經由上面分析,得知readcookie.cgi可以建立空seeeionidConfigsubmit.cgi可以設定Telnet及FTP服務,為了便於操作,此處使用Firefox示範。(192.168.232.139 是筆者電腦啟動LV2映象檔後的網址,請依個人環境修正

一、 在瀏覽 https://192.168.232.139/cig-bin/readcookie.cgi,會得到如下結果,重點在於session is 的內容是空的

二、啟用 FireFox的開發者模式,切換到「網路」頁籤。

三、瀏覽https://192.168.232.139/cig-bin/Configsubmit.cgi,出現404是正常的。 

四、從「網路」頁籤的網址清單中選擇剛剛請求的Configsubmit.cgi,然後點擊右方的「重新發送」下拉選單,並選擇「編輯並重新發送」項目。

五、將方法改成「POST」,並在請求內容中貼上「Telnet=on&FTP=on」,然後「傳送」。

六、查看回應結果,FTP及Telnet已經打開。

假設您已按照簡報30頁的方法執行暴力破解,應該已得到作業系統的 admin / Administrator 這組帳密,可以利用telnet操控這台設備了!

2018年5月12日 星期六

解決tomcat上 X-Frame-Option及X-XSS-Protection未設定的問題

最近剛上了一個JSP開發的系統,部署在tomcat 8.5上,被本機關滲透測試團隊發現兩項表頭未設定,被列為中風險,分別是「X-Frame-Options」及「X-XSS-Protection」,如果在IIS,這很好處理,只要在「HTTP回應標頭」裡加兩項設定就可以解決。但從網路上找到的tomcat上解決方案大多要自己寫filter,其實tomcat自7.0.63版以後,也可以透過web.xml來設定,只要在web.xml加入:
filter>
   <filter-name>httpheadersecurity</filter-name>
   <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-classinit-param>  
       <param-name>antiClickJackingOption</param-name>  
       <param-value>SAMEORIGIN</param-value>  
   </init-paramasync-supported>true</async-supported>
</filter
filter-mapping>
   <filter-name>httpHeaderSecurity</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
</filter-mapping
當啟用 httpHeaderSecurity 的filter後,預設是將X-Frame-Options=DENY加到回應標頭,但因我的系統需要用iframe內嵌同一網站的頁面,所以要自己加:
init-param>  
    <param-name>antiClickJackingOption</param-name>  
    <param-valueSAMEORIGIN</param-value>  
</init-param
才能將X-Frame-Options的值改成SAMEORIGIN,要注意哦!param-nmae是用antiClickJackingOption(注意大小寫),不是X-Frame-Options
不過httpHeaderSecurity只能設定幾種標頭,不像IIS的「HTTP回應標頭」可以隨便設,如果你想要設定任意標頭,只好自己寫filter,這裡提供個鏈結供參:
https://stackoverflow.com/questions/38195273/how-to-set-x-frame-option-in-tomcat

2016年9月10日 星期六

ASP 網頁程式使用aspSmartUpload元件部署於 IIS 8.5
(Windows Server 2012 R2)注意事項

一般來說,將ASP部署到 IIS 8.5 的預設環境並沒有問題,但若程式中有使用外部元件,例如 aspSmartUpload,有些設定就必須調整。
由於 ASP 是古早的系統,外部元件通常不會再更新版本,可能依舊停留在 32bit 模式,所以應用集區(Application Pool)要「啟用32位元應用程式」:
1. 切換到應用程式集區資料夾
2. 從集區清單中選擇用於 ASP 應用程式的集區
3. 使用右邊「動作」內之「進階設定」
4. 將「啟用32位元應用程式」設為 True。

另有關註冊aspSmartUpload方式:
請在 C: 的根目錄建立 aspSmartUplaod 資料夾,並將 aspSmartUpload.dll 及 aspSmartUploadUtil.dll 複製到此資料夾中;同時也複製到 C:\Windows\Sysem32C:\Windows\SysWOW64。(不要將資料夾置於 C:\Windows 之下,否則元件可註冊成功,但執行時,可能會無法產生物件)
註冊 aspSmartUpload中的aspSmartUpload.dll,開啟命令提示字元
C:\Users\user>cd C:\aspSmartUplaod\
C:\aspSmartUplaod>C:\windows\SysWOW64\regsvr32 aspSmartUpload.dl
 
除了aspSmartUpload.dll的註冊外,還要注意開啟儲存檔案的目錄及上傳過程中暫存區的寫入權限!

2016年3月21日 星期一

如何將文字檔由 big5 轉成 utf-8

會有這個需求是因為我負責的Web應用程式有20多個,開發時間從民國89至今,早期網頁開發多數採用 big5,近年來隨著 unicode 盛行,近期開發的網頁系統也轉用 utf-8,為讓舊系統跟新系統字碼漸趨一致,所以逐一改寫系統。
要將 big5 的系統改成 utf-8,除了<meta http-equiv="Content-Type" content="text/html; charset=big5"> 中的 big5 改成 utf-8 外(這好處理),還要將所有網頁及後端程式碼的檔案轉成 utf-8 格式,這項工程不小,之前利用批次轉檔工具,雖然速度很快,但發現轉檔後,有時中文字會變成亂碼
幸好,notepad++ 也有轉碼功能,比起批次轉檔雖然步驟多了些,但截到目前為止還未發現中文出現亂碼問題。
首先可以一次拖拉多個檔案到 notepad++,然後檢視右下角,如果 UTF-8 表示此檔案已是UTF-8內碼,就不用轉換了。如果是 ANSI,即檔案內碼為 Big5,此時只要從「編碼」功能表選擇「轉換至UTF-8碼格式」,再存檔即可

ASP.NET 在 Redirect 之後 Session 遺失(Session lost after redirected)

2013年曾寫了一篇關於「保護 Cookie 的安全(Secure 與 HttpOnly)」的博文,原由是Web系統進行黑箱掃描時,出 [加密的階段作業 (SSL) Cookie 中遺漏安全屬性] 的弱點,在 .Net 2.0 之後,這個問題可以透過 Web.config 中加入「<httpCookies httpOnlyCookies="true" requireSSL="true" />」(在<system.web>區段內)來增加安全性。
但啟用<httpCookies httpOnlyCookies="true" requireSSL="true" />後,進行Debug時會發現使用者經Login.aspx網頁完成登入後,原本將帳號資訊記錄到 Session 之中,並執行FormsAuthentication.SetAuthCookie 將狀態記錄 Cookie,在執行 FormsAuthentication.SetAuthCookie 之後,Session 物件確實已建立,隨者利用 Response.Redirect 轉址到作業的頁面後,又被導回 login.aspx,利用trace 發現轉址到作業頁面時,Session 被成空的。
在網路上找了很多資料,高手建議的解法有:
  • Response.Redirect("work.aspx", false)
  • FormsAuthentication.RedirectFromLoginPage
  • Server.Transfer
這三種都試了,問題依舊,最後是將 <httpCookies httpOnlyCookies="true" requireSSL="true" /> 這一段的 requireSSL="true" 刪除掉問題就不見了。 原來個人開發用的環境沒有啟用 SSL ,遇到 requireSSL="true" 才出問題,如果將測試環境的IIS 之 SSL 啟用,加上 requireSSL="true" 這個屬性也能正常工作。

2014年6月8日 星期日

Google 部落格(blogger.com、blogspot)為何無法顯示中文罕字?

在Google上寫中文部落格的人不知有沒有發現,如果中文字是Unicode 第0字面以外的字時,編輯時不會出現亂碼,可是正式發佈時,卻出現方塊字,例如:

這幾個字,在編輯時並未出現亂碼,但「預覽」時卻變成了方塊字,碰到這種狀況只能手動將這些字以 Html number 方式表示,可是~~ 要怎麼知道這些字的 html number?我的做法是利用 Word 小算盤!

中文罕字轉換成 Html Number
  1. 先將這些罕字複製到 Word 裡。
  2. 將游標停在每個字的後面,然後按 Alt-x,Word就會將中文字轉成 Unicode
  3. Word 轉換出的 Unicode 是十六進制,所以要再利用小算盤的「程式設計師」模式轉成十進制
    1. 先確認小算盤是在「程式設計師」模式,輸入模式為「16進位」及「Qword」
    2. 將 Word 轉出的16進位碼貼到小算盤裡,然後改選「10進位」,就可以看到此 Unicode的 10 進位碼
    3. 接著將中文字改成html number,例如「𠁇」就改成&#131143;
所以「𠁁𠁇𠁔𠁘」都改成「&#131137;&#131143;&#131156;&#131160;」 如果罕字都改成 html Number,結果卻都變了字,那是因為部落格的選項」之「撰寫模式」沒設成「解譯輸入的 HTML」,只要切換至「解譯輸入的 HTML」再發佈就可以正常顯示了!

讓Windows 7支援全字庫的 Unicode 第15字面字型

Windows 7 依循 Unicode 5.0,提供細明體、新細明體、(簡)宋體的Unicode 第0字面(BMP)及第2字面的中文字型共七萬餘字,再加上BMP的使用者造字區6400字供使用者自行擴充,一般使用已經足夠。
但中文字以型為主,可以變化多許多相似型體,超出目前 Unicode已定義的範圍,為了處理這些字,由行政院研考會(已併入行政院國家發展委員會)發展的全字庫unicode 第15字面的宋體(即明體(註1))及楷體字型各18000多字。這些字體可以從「http://www.cns11643.gov.tw/AIDB/cns_authorization_apply.do」下載(授權說明見:http://www.cns11643.gov.tw/AIDB/copyright.do)
原本我以為安裝了字型檔就可以顯示文字,但安裝以後才發現除了「全字庫正楷體」(第0字面)外,「全字庫正楷體Ext-B」(第2字面)及「全字庫正楷體Plus」(第15字面)在 MSWord 2010 沒有作用 (Excel 及 PowerPoint 可支援),為什麼會發生這種事?原來Word 會自己判斷字型檔的適用語系(CodePage),而全字庫的 2、15字面字型的CodePage 只設為 437 (US),只要 CodePage 多勾選 950(繁中)即可正常(註2)。
全字庫正楷體可以正常使用

全字庫正楷體第2字面在Word2010無作用,仍自動選用新細明體字型

全字庫正楷體第15字面在Word2010無作用

但多勾選 CodePage950 也僅是在應用程式中「可選擇套用」第15字面字型,對於只能選用單一字型的系統(如檔案總管、記事本)還是無法正常應用。為了讓OS可以自動選用第15字面的字型,必須對 Windows 7的註冊表(使用 regedit.exe)做些修改
未完成註冊表修改前,不會自動引用 TWKaiPlus

未完成註冊表修改前,不會自動引用 TWKaiPlus
為了操作方便及對比,我已利用  FontCreater 將「全字庫正楷體Plus」的字體名稱更名為 「TWKaiPlus」,所以我的系統裡同時存在「全字庫正楷體Plus」及「TWKaiPlus」兩套字型。
註冊檔修改內容:
  1. 先確定  HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts 資料夾內應有一組 TWKaiPlus (TrueType) TW-Kai-Plus-98.ttf,表示字型安裝成功
  2. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink 資料夾內新增一組「多字串值」
    TWKaiPlus
    MICROSS.TTF,40,48
    MICROSS.TTF
    MINGLIU.TTC,MingLiU
    SIMSUN.TTC,SimSun
    MSMINCHO.TTC,MS Mincho
    BATANG.TTC,BatangChe
    此設定的目的是:引用 TWKaiPlus 時,如果遇到 TWKaiPlus 裡沒有的字型,就依序到 MICROSS.TTF、MINGLIU.TTC...裡去找字體
  3. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanauagePack 新增一 DWord 值:
    SURROGATE:2
    此設定值是啟用 Windows 7的Unicode SURROGATE機制
  4. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanauagePack\SurrogateFallback 新增一「字串」值:
    Plane15:TWKaiPlus
    此設定值是啟用 第15字面字型的引用對象,指向 TWKaiPlus
  5. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanauagePack\SurrogateFallback\MingLiU 新增一「字串」值:
    Plane15:TWKaiPlus
    此設定值是對引用「細明體」時,如有第15字面字型時,指向引用 TWKaiPlus
  6. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanauagePack\SurrogateFallback\PMingLiU 新增一「字串」值:
    Plane15:TWKaiPlus
    此設定值是對引用「新細明體」時,如有第15字面字型時,指向引用 TWKaiPlus
  7. HKCU\Software\Microsoft\Internet Explorer\International\Scripts\42
    IEFixedFontName:TWKaiPlus
    IEPropFontName:TWKaiPlus
    此設定值是設定IE 引用第15字面字型,指向 TWKaiPlus
完成註冊表設定後,重新登入(或開機),您會發現使用「新細明體」或「細明體」的地方如果有用到第15字面的字時,會自動以 TWKaiPlus 顯示。
完成註冊表修改後,雖然選用「新細明體」,第15字面會自動選用TWKaiPlus
完成註冊表修改後,就算Visual Studio,第15字面也會自動選用TWKaiPlus
一天所需蜨󿿸𢓌𢓍𢓎󿿺𢓍一abCD󿿻󿿼12
一天所需蜨󿿸𢓌𢓍𢓎󿿺𢓍一abCD󿿻󿿼12
在您的電腦,上面的紅字第2、15字面的字應該都看不到,那是因為這個部落格應用程式的設計只支援到 16 bits 編碼,而 2、15字面編碼會用到 32 bits,結果就是一個字被拆成兩個字,這是 Google 部落格設計的問題。不是瀏覽器顯示的問題,千萬不要說瀏覽器不支援15字面,只要有適當的字型檔,網頁在 IE、 Chrome、Firefox都可以正常顯示。

但是...,不是每種應用軟體都支援Windows 7 的自動延申機制,經測試:
  1. Word、Excel 如果選擇「新細明體」或「細明體」時,15字面會留下空格,但如果選擇「TWKaiPlus」,則 0、2、15字面的字都可正常顯示。
  2. PowerPoint 可正常使用,不論選「新細明體」、「細明體」或「TWKaiPlsu」都可以正常顯示。
  3. IE 可以正常顯示,在 FireFox 及 Chrome 第15字面的字體會變成方格
    (這是指瀏覽器本身對字體的支援,並不會影響網頁的顯示)
不同瀏覽器第15字面的支援不一樣!

註1:明體實際應為宋體,明體是日本的用法。
註2:有關設定方式,請參考「修正全字庫的第2、15字面字型檔,讓 Word2010 可正常使用

2014年5月9日 星期五

關於VS2003開啟 .NET 1.1專案「Visual Studio .NET 無法建立或開啟應用程式。...」另一種可能

也計有人問現在都VS2013了,還在談 VS2003,但接案是沒得選擇的!

最近為了修正一組舊專案,不得已重回 VS2003,這個專案是在2008~2009年間開發的,當時開發環境是 XP + IIS 6,後來配合設備升級,把開發環境改成 Win7+IIS 7.5,於2013年7月曾經在新環境修改過一次,之後就沒有再動它了。
今天又再次開啟此專案,結果~~~~,出現了如下的畫面:

碰到問題,當然先上網找答案:
  1. VS.NET]VS.NET 2003開啟Web專案時,發生「無法建立或開啟應用程式」,這一篇解決的是「連線身份」的問題
  2. VS2003 開發 ASP.NET 1.1 常見問題,這一篇說的是目錄路徑的問題
  3. 還有的是說要重新執行 ASPNET_REGIIS.EXE -i
總之會出現這個錯誤的原因可能不止一種,上面這些解法在我的開發環境上都無效,原來我的問題是另一種形態,原因是本機關從今年起,為了控管個人電腦權限,減低PC被駭客控制時造成的損害,所以開機登入的帳號都只有一般使用者權限

解決的方法:以系統管理員身份執行 VS2003


如果要偷懶,就將 Visual Studio .Net 2003 的相容性之特殊權限等級的「以系統管理員的身分執行此程式」勾選,則以後就會自動以以系統管理員身份執行 VS2003。

2014年5月4日 星期日

常見的 Web AP 安全漏洞

網頁應用程要設計的安全很不容易,因為網頁的原始碼會傳送到瀏覽器端,駭客可以從容地分析網頁原始碼、Request 及 Response 的標頭,可以嘗試各種不同的攻擊 payload! 有些弱點雖然專家一再提醒,但許多網頁(網站)卻一再出現,甚至許多程式設計師故意忽略這樣的弱點、或者不知如何修正這些弱點
底下是我幾年來參與黑白箱掃描及滲透測試的心得,是程式設計常疏忽的地方:
  1. 圖方便,用變數串接方式產製查詢字串或動態命令!
    使用變數串接可以簡化程式碼撰寫,所以程式設計師理所當然優先選擇這種撰寫方式,尤其涉及較多變數(參數)時,使用變數串接可節省更多程式碼,相對也省下許多時間。
    程式設計師圖一時方便,因此造就了 Injection  漏洞,當被發現系統存在這種漏洞時,有些程式設計師不思正統的寫法,反而自己撰寫過濾程式(見8.),當然不是自己寫作的機制就不好,只是沒有經過有效驗證,或許不如自己想像那麼強固!
  2. 以為使用者會乖乖輸入規定的資料格式
    許多新手設計師以為使用者會照著設計規格書上說明的輸入資料,甚至自己測試時,也只會輸入「合法」的資料來驗證功能,完全不在意「違規」的資料格式,不會適當處理違規的資料,因此提供駭客一道可敲測的通道! (駭客就是不按牌理出牌)
  3. 以為 javascript 可以實現資料驗證或授權
    這是我遇過最多的漏失(還有 4.),甚至有設計師跟我爭論他的系統已盡到相當完善的防護,還當場測試以驗證他的論點, 可惜他並不知曉許多瀏覽器的外掛(Plugins)都可以協助繞過javascript檢核,甚至駭客進行滲透是不用常規瀏覽器的! javascript 驗證或授權就像紙上畫的鎖,一般使用者會以為有鎖,但小偷卻毫不費力就可以突破。
  4. 以為使用者看不到隱藏欄位內容
    如同 3. 一樣,這種漏失也很常出現,其實只要「查看網頁源始碼」就可以看見隱藏欄位的內容,完全不需要特殊技巧, 所以不該利用隱藏欄位傳遞機敏資料。
  5. 不明白或故意忽略Cookie 防護的重要性
     很多設計師會利用Coolie 來儲存資料,以便在不同網頁間交換資料,卻不明白Cookie 的運作原理,其實Cookie 是以純文字模式儲存在 Client 端,有很多工具可以修改Cookie的內容,因此 Cookie 不是安全的儲存體,不該用 Cookie 來存放如帳號、密碼或角色等資訊,以免被篡改而不自知。
  6. 使用 WebService ,卻忘了每次叫用時都需求再認證
     初學用WebService的設計師會以為 WebService 不會獨自運作,一定是透過他的程式才會被呼叫(把WebService 跟一般的程式庫或物件API搞混了),其實只要 WebService 沒有適當防護,「任何人」都可以命令它工作,所以採用 WebService 機制比一般 Web AP 更需要費心在網頁安全上。所以在每一個WebService 方法的進入點都要執行身份驗證及授權
  7. 以為限制網頁欄位的輸入長度,可以防止複雜的注入攻擊指令
     如同 4. 一樣,屬於自以為...的心態,同樣的,瀏覽器的外掛或 Local Proxy 都可以繞過這層限制,而無限制的輸入(傳送)超長資料。
  8. 自認自己寫成的特殊符號過濾程式就可以達成防注入的功能
     是的,許多自負的設計師會自己開發濄濾程式,避掉特殊符號,以為這樣就可以防止注入攻擊,的確,過濾掉特殊符號可以防止9成以上的注入攻擊,可是剩下的1成才是駭客最常用的攻擊方式,如果可以,建議還是採取正統的撰寫模式。

上面提的這些只是常見的,幾乎用手動測試就可以發現的漏洞算是最基本網頁安全的課題,希望可以給程式設計師資安防護的基本參考,同時提供初入網頁滲透測試者基本的偵查方向。

2013年7月29日 星期一

保護 Cookie 的安全(Secure 與 HttpOnly),在ASP.NET環境

Cookie 的 Secure 屬性是強迫 Cookie 在傳輸時使用 SSL 加密機制。
Cookie 的 HttpOnly 屬性是指示 Cookie 只供瀏覽器與WebServer之間之網頁溝通使用,不允許JavaScript 存取Cookie (document.cookie)。

一、於程式中產生的Cookie,可以利用 HttpOnly 及 Secure 屬性,針對特定的 Cookie 要求
myCookie.HttpOnly = true

myCookie.Secure = true;

二、透過 WebConfig 設定,讓所有的 Cookie 都啟用 Secure:
 ASP.Net 2.0 以後,可以在 WebConfig的 <system.web>區段內加入:
<system.web>
   <httpCookies httpOnlyCookies="true" requireSSL="true" />
   ....
</system.web>

但上面的設定方式,在ASP.Net 1.x 並不支援,所以必須在 Global.asax 中動手腳:
在Global.asax.vb 中加入下面這一段程式 ,強制每一個Cookie 都加入指定的屬性

   Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' 於每一個要求開始時引發
        For Each sCookie As String In Response.Cookies
            Response.Cookies(sCookie).Secure = True
            Response.Cookies(sCookie).HttpOnly = True
        Next
    End Sub

三、 Secure HttpOnly 是兩個屬性,請視需要設定(即沒有必須同時都設)

四、雖然完成上面的設定,可以讓應用程式在傳送 Cookies 時加入 Secrure 及 HttpOnly=true 的旗標,但 ASPX 的 SessionCookie (.ASPXAUTH) 卻仍無法以 SSL 傳送,弱點掃描時會發生「Cookie Security: Cookie Not Sent Over SSL」的風險,解決方式是在 中加入 requireSSL="true",如下所示:
<authentication mode="Forms">
  <forms loginUrl="http://mojsingle.moj/mojsingle/script/mojlogin1.asp" timeout="30" protection="All" requireSSL="true" />
</authentication>

-------------------------------------------------------------------------------------------------
緣由:
早期的 ASP.NET 程式最近被黑箱掃描程式找到一項「中風險」項目:
[加密的階段作業 (SSL) Cookie 中遺漏安全屬性]

測試類型:
 應用程式層次測試
威脅分類:
 應用程式隱私測試
原因:
 Web 應用程式會透過 SSL 傳送未受保護的 Cookie
安全風險:
 有可能竊取在加密階段作業期間傳送的使用者和階段作業資訊 (Cookie)
CWE:614
技術說明:
 在應用程式測試期間,偵測到在加密階段作業中,所測試的 Web 應用程式設定了不含 "secure" 屬性的 Cookie。
 由於這個 Cookie 未包含 "secure" 屬性,因此,也可能在未加密的階段作業期間將它傳給網站。

由於此 Cookie 並非我程式中產生的,而是系統為 Session 所建立,為解決此一中風險弱點,只好採用 Global.asax.vb 中加入控制程式的方法因應!

2013年6月23日 星期日

利用javascript實做 MVC 網頁(六)

雖然一直想儘量減少在網頁上嵌用後端的程式碼,但如果網頁不和後端溝通就無法實現Web2.0的互動性,所以就思考是否有一個準則,上圖就是我想到的標準!
  1. 如果Request 的對象是一般靜態網頁(這種網頁根本不需任何 ActivePage支援)、或初始時之欄位內容都是固定的(例如都是以空白開始),因為Response 前不需先進行任何處理,所以就直接回應即可,網頁亦不需內嵌任何後端程式碼,甚至網頁都可以用  .htm/.html 的副檔名。
  2. 如果網頁是接收自其他網頁的要求(Post/Get),而用其他網頁的欄位內容做進一步處理時,因為本網頁本身沒有處理Form的邏輯,所以利用內嵌在頁面的後端函數(ParaFetch)將需求網頁之 Form 欄位組合成 Key:Value 對,此時會將 Key:value  以JavaScript 物件方式,指定給本網頁,所以在本網頁載入完成後,再由 window.onload 事件以AJAX方式向後端要求處理這些 key:value ,後端將處理結果回傳後,再利用 FormRender 來展現頁面。
  3. 第三種不建議使用,因為會破壞使用這種架構的原則,但有時為了方便,而且網頁是最終結果,不需再做其他後續的操作,就直接利用 ASP.NET 在後端 Render 網頁內容(例如報表等)

2013年5月23日 星期四

利用javascript實做 MVC 網頁(五)

離發想到現在竟然不知不覺過了一年了! 這期間一直在想如何精簡實作的方法,好讓這種開發模式可以容易實做。經過前面幾篇的說明,在此先做個小結,草擬設計原則,以利設計參考:
(一)對資料庫的存取、控制寫在 Module內,其他程式(Control, View)不能包含任何存取資料庫的功能--以「物件」方式實作對資料庫的存取,提供函數(method)呼叫供Control使用
(二) Module  只實作業資料庫的存取功能,不作其他額外功能。
(三) Control  :
  1. 負責接收 View Submit過來的資料及回傳處理結果。
  2. 負責所有的商業邏輯的計算(處理)。
  3. 如果要查詢資料庫,只將查詢參數傳遞結 Module 的函數(method),並接收 module 回傳的查詢結果。(Control 不自己做 SQL 的查詢語法 )
(四) View 負責所有前端的Presentation的功能:
  1. View 傳送表單資料或使用者操作給 Control,Control用 JSON 或 Response 回傳處理結果。
  2. View 收到結果後,由View 決定回傳值的操作,Control 只負責傳回結果,不負責控制 View 的表現方式。
(五) 由於View 內容包含:HTML(網頁), CSS(外觀佈局), JavaScript(行為控制),為了實現網頁設計(HTML + CSS) 與行為控制設計(JavaScript) 分開,建議:
  1. 有關網頁的 Javascript 建議以 <script type="text/javascript" src="網頁名.js"></script> 方式自外部引入。
  2. 如果共用的 javascript  檔案,置放於根目錄下的 JS 子目錄,如果是特定網頁專屬的Javascript 檔案,則與網頁置於同目錄下,並採用相同主檔名,以利管理
  3. 有關各DOM物件的事件處理,請利用 jQuery 的 $("#id").EVENT=function(){ }; 方式註冊,不要直接寫在 Html 的 tag 內。
利用這種開發模式,個人見解應有下列優點:
  1. 網頁、Javascript、Control、Module 可以分開設計、測試,也就是可以平行開發。
  2. 各功能間是透過功能呼叫 (參數傳遞)方式合作,對於通用的功能(例如:可能許多網頁都會叫用相同的資料)只需寫一個即可共用! 減化開發程序及版本維護。
  3. 由於各功能獨立模組化, 可供其他專案使用,達到程式再用目標。
  4. 為客戶展示用的雛型網頁可以幾乎不修改就直接移作正式開發用,讓客戶獲得一致的感受
依照上述原則,應該可以達到 DB管理、程式設計與網頁設計分離的要求。
由於個人思考範有限,若先進有發現不足之處,尚請隨時指正!

2013年5月22日 星期三

利用javascript實做 MVC 網頁(四)

前言:

利用javascript實做MVC 網頁(二) 談到如何將 A 網頁的表單資料 POST 給 B 網頁(在 B網頁後端接收後,轉成 javascript 物件,以 <% =變數 %> 方式嵌入網頁中。
利用javascript實做 MVC 網頁(三)中談到如何將後端處理的結果,如何以物件方式返回給網頁內的呼叫程式。

一般由 jQuery.ajax 呼叫後端程式時(詳見:利用jQuery -Ajax 叫用 ASP.NET 的幾種方式),如果要傳送的表單欄位,則在 ajax 中的 data: 屬性設定欲傳送的 Key:value (值對),如:

data: JSON.stringify({field1:value1, field2: value2, field3:value3})

在接收端,如 WebService 或 PageMethod 則利用函數的參數:

METHOD(string field1, string field2, string field3)  來接收表單欄位內容

註:參數是以名稱對應方式,而非順序對應!

如果表單欄位數二、三個,使用這種傳直方式還不會有多大問題,如果表單位有二、三十個,那參數不是要寫到天邊去了!  顯然參數名稱對表單欄位的方式就不太合用! 這時候我們可以改用字典物件(Dictionary<>)方式來接收!
前端利用 form2json 將表單所有欄位轉成 JSON 物件

data:JSON.stringify({args:form2json("#myform")})

接收端改成

METHOD(Dictionary<string, string> args)
{
   var 變數 = args["欄位名稱"];   //就可以取得傳來的值了!
}


form2json 程式碼如下:
function form2json(formId)    //formId 是要加入 JSON 的表單 id 
{
    var data = new Object();
   $(formId +" :input:not(:button, :reset, :submit)").each(function()
    {
        if($(this).attr('type')=='checkbox')
        {
                data[$(this).attr('name')]=($(this).attr('checked')) ? 1 : 0 ;
        }   else     {
            data[$(this).attr('name')]=$(this).val();
        }
    });
    return data;
} 

後記:自己改寫了一支 jQuery Extention,只要在網頁引入:
 <script type="text/javascript" language="javascript" src="js/cmj.toJSON.js"></script>
然後在 data 用
data: JSON.stringify({arg:$('#myform').toJSON()}),
就可以輕鬆將表單欄位組成 JSON 物件了!

使用jQuery.ajax呼叫 WebService或 ASP.NET 在後端程式指定轉址路徑

  當利用 jQuery ajax 呼叫或Post 給後端 ASP.NET處理時,如果要指定轉址的路徑,可以將返回值用  「window.location.replace("路徑");」  或  「window.location.href ="路徑";」,以字串方式回傳給呼叫的 ajax。
在 ajax 的 success 回呼程序中再利用
   evel(回傳值)
方式來轉址即可!

其實還有很多種方式可以處理,但遺憾的是無法直接在後端程式碼使用:
Response.Redirect("路徑");  的方式來轉址,只能利用前端網頁轉址!
註:用  Server.Transfer("路徑"); 也不行

2013年5月21日 星期二

利用jQuery -Ajax 叫用 ASP.NET 的幾種方式

  jQuery 真是個佛心的發明,它讓前端叫用後端服務的方式更加靈活,使用 jQuery 之 ajax 呼中不同標的之差異:
呼叫  WebService :可用 JSON 或 Key:Value 傳送Form的欄位。
      如果用 return 回傳值,則dataType 要設成 "json"
      如果用 HttpContext.Current.Response.Write 回傳值,則 dataType 設成 "html" 或 "text"
呼叫 PageMethod:只能用 JSON 傳送 Form 欄位。
     只可用 return 回傳值,且dataType 要設成 "json",否則會收到字串形態的 JSON 物件
呼叫網頁(ASPX):只能用 key:value 傳送 Form 的欄位。
     只可用 HttpContext.Current.Response.Write 回傳值,則 dataType 設成 "html" 或 "text"

壹、配合 JSON 呼叫 WebService (ASMX)

處理結束之後,會用 return 返回處理結果,返的資料

$.ajax({
        url: 'user.asmx/checkLogin',
        type: 'POST',
        async: false,
        data: JSON.stringify({userId:'12345', password:'12345'}), 
        contentType:'application/json; charset=UTF-8',
        dataType:"json",      //如果要回傳值,請設成 json
        error: function(xhr) {//發生錯誤時之處理程序 },
        success: function(reqObj) {//成功完成時之處理程序 }
     }); 

底下是 user.asmx 的後端程式碼
using System;
using System.Web;
using System.Web.Services;
using System.Web.Security;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Web.Configuration;
using System.Text.RegularExpressions;

[WebService(Namespace = "http://SSO_Portal.moj.tw/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// 若要允許使用 ASP.NET AJAX 從指令碼呼叫此 Web 服務,請取消註解下一行。
[System.Web.Script.Services.ScriptService]
public class SSO_Service  : System.Web.Services.WebService 
{
    [WebMethod(EnableSession = true)]
    [System.Web.Script.Services.ScriptMethod]
    public string[] checkLogin(string userID, string password, string grCode) 
    {
        UserData user=new UserData();

        HttpContext.Current.Response.Redirect("Default.aspx");
        return null;
     }
}


貳、配合 JSON 呼叫 PageMethod

 處理結束之後,會用 return 返回處理結果,返的資料

$.ajax({
        url: 'checkLogin.aspx/chkUser',
        type: 'POST',
        async: false,
        data: JSON.stringify({userId:'12345', password:'12345'}), 
        contentType:'application/json; charset=UTF-8',
        dataType:"json",       //如果要回傳值,請設成 json
        error: function(xhr) {//發生錯誤時之處理程序 },
        success: function(reqObj) {//成功完成時之處理程序 }
     }); 

底下是 checkLogin.aspx 的 chkuser 後端程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;

namespace mySpace
{
    public partial class checkLogin : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
 
        [WebMethod(EnableSession = true)]
        public static string chkUser(string userID, string grCode, string password)
        {
            string aaaa = "";
//          string uid=HttpContext.Current.Request.Form["userID"];  //收不到值
//          string pwd = HttpContext.Current.Request.Form["password"];
//          HttpContext.Current.Response.Redirect("Default.aspx"); //會出錯
            return null;
        }
     }
}


參、直接 POST 給另一個網頁(ASPX)

直接在處理的網頁內,用 Response 返回資料內容

$.ajax({
        url: 'checkLogin.aspx',
        type: 'POST',
        async: false,
        data: {userId:'12345', password:'12345'}, 
        contentType:'application/x-www-form-urlencoded; charset=UTF-8',
            //如果使用 "application/json; charset=utf-8" ,則後端程式無法
            //用 Request.Form["..."]  來取得傳送過來的資料
        dataType:"html",     //或用 "text"
            //如果不指定 dataType,會造成 jQuery 剖析時錯誤,所以會觸發 error
        error: function(xhr) {//發生錯誤時之處理程序 },
        success: function(reqObj) {//成功完成時之處理程序 }
     }); 

底下是 checkLogin.aspx 的後端程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;

namespace mySpace
{
    public partial class checkLogin : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
           String userid = this.Request.Form["userId"];
           String pwd = this.Request.Form["password"];
           this.Response.Write("Return Value");  //要返回的文字
           this.Response.Redirect("Default.aspx"); 
           //會把整個 Default.aspx 的html內容回傳,而不是執行轉向作業!
           Server.Transfer("default.aspx"); 
           //會把整個 Default.aspx 的html內容回傳,一樣不會執行轉向作業!
        }
     }
}


說明:

jQuery 的 contentType 對不同後端程式的影響

 application/x-www-form-urlencoded application/json
對WebService
  1. data: 不能序列化,否則會出錯
  2. 可由參數接收(用名字對應),接收參數不一定要等於傳送之個數
  3. 可由 HttpContext.Current.Request.Form 請值
  4. 可用HttpContext.Current.Response. Redirect("../Default.aspx"); 傳送網頁
  1. 只能透過參數接收傳過來的資料
  2. data: 一定要序列化,否則會出錯
  3. 不能使用 HttpContext.Current 物件(編譯時不會錯,執行時會錯!)
對ASPX網頁
  1. data: 不能序列化 JSON.stringify()
  2. 可由 this.Request.Form 請值
  3. 可用this.Response. Redirect("../Default.aspx"); 傳送網頁
  1. 可以呼叫網頁程式,但無法接收 Form 欄位資料
對 PageMethod不能使用這種方式呼叫 PageMethod,否則會變成是 Post 到 ASPX,反而執行 Page_Load,而忽略指定的 PageMethod


  1. 只能透過參數接收傳過來的資料
  2. data: 一定要序列化,否則會出錯
  3. 可以用 HttpContext.Current.Request.Form 但收不到值!
    4.不能使用 HttpContext.Current 物件(編譯時不會錯,執行時會錯!)
序列化:用JSON.stringify({})



jQuery.ajax() 的一般重要參數設定

accepts:??不清楚要設成什麼值??
async:true 是否採 非同步 呼叫,跨網域呼叫 及 dataType:"jsonp" 不支援 同步呼叫
beforeSend:function(jqXHR, settings){}  執行ajax之前先執行此callback程序,例如更改檔頭、 如果返回 false ,就會中止 ajax
cache:true | false
complete:function(jqXHR, textStatus){} 在 success 或 error 之後執行
  txtStatus 可能為 "success", "notmodified", "error", "timeout", "abort", or "parsererror"
contents: 指明針對後端回傳的資料, jQuery 要如何剖析? ????
contentType
    "application/x-www-form-urlencoded; charset=UTF-8"   用一般文字對傳送參數
    "application/json; charset=utf-8"                    用 json 物件傳送參數
converts: ????dataType-to-dataType converters
  {"* text": window.String, "text html": true, "text json": jQuery.parseJSON, "text xml": jQuery.parseXML}
crossDomain: false 是否允許跨網域 呼叫
data: {key:value, key:value} 要傳送的資料
dataFilter: function(String data, String dataType) 如何處理由後端回傳的原始資料
dataType:"xml", "json", "script", "html", "jsonp" 指明回傳資料的形態,預設是由 jQuery 自行判斷
scriptChartset: 只針對 dataType 設成 script 或 jsonp 是指定其內碼字集
error:function(jqXHR jqXHR, String textStatus, String errorThrown )
headers:{key:value, key:value} request 時,加入額外的表頭資訊
processData:true 預設 data: 選項的資料是會依照 contentType 進行轉換,如果不想轉換可將 processData 設為 false
success:function(PlainObject data, String textStatus, jqXHR jqXHR )
timeout:N 設定 timeout 的時間(毫秒)
type: "GET" 或 "POST" ("PUT", "DELETE" 也可使用但不一定有作用)

2013年5月17日 星期五

不同的預設字型,讓使用者誤解了!

  做網頁的人很厲害,會在 CSS中先指定網頁的預設字型,如此一來可以避免因沒有指定字型,而使用者又自己選定瀏覽器預設使用字型造成的困擾!

這一點寫 Web Ap 的人就考慮得那麼周到了!

  一般網頁如果不指定字型,瀏覽器在展示網頁內容時,就會使用瀏覽器設定的預設字型:
IE --> 工具=>網際網路選項=>「一般」頁籤=>「字型」鈕=> 可以針對不同語言選定不同的預設字型,如果沒要調整,原設為 新細明體與細明體

FireFox-->工具=>選項=>內容=>「字型與色彩」=>進階

  也就是說,使用者可以選擇自己瀏覽器對文字的預設字體,當然要選用的預設字體必須是此台電腦有安裝的才有用!
-------------------------------------------------------------------------------------------------------------------------------
今天就碰到這種的怪事(還是麻煩事!)

   我負責的系統中,有一個人才資料查詢,當輸入姓名部份文字,可查到符合條件的人才資料。這個系統是民國89年時用vb6開發的,所以輸入「眞」字時,會被轉成 ? 存到資料庫內。

  恰巧有個客戶,她的名字中有一個古字的「眞」,她不同意我們用「真」字代用,所以她的「眞」字在這個系統就變成了「?」

  這位客戶就用「真」字查,果真查出許多名字有「真」字的人才清單,因為在清單頁有指定用「標楷體」,所以顯示為「真」,但是選定某一人才後,會顯示更詳細資料,因為詳細資料頁沒有指定字形,一般我們都以為會自動使用細明體或新細明體,但顯然我錯了! 我沒有注意到瀏覽器可以指定預設字體(學藝不精!),這位客戶應該有自行變更預設字體,所以在她的瀏覽器上會顯示成「眞」!

  所以她就說即然在詳細資料可以顯示成「眞」,要求她的「眞」字不能顯示成「?」~~~可是別人電腦不見得有她用的字體,這 ~~不是更為難了嗎? 因為她看到「眞」,別人看到「真」,這~~~算不算同一個字呀!
--------------------------------------------------------------------------------------------------------------------------
看來以後最好每個網頁都先預先指定字形才不會引起誤會!

2012年5月1日 星期二

利用javascript實做 MVC 網頁(三)

前面利用javascript實做 MVC 網頁(二) 已說明如何將Submit 的 Form 傳給後端的程式,也說明後端程式如可將對應的欄位資料及屬性以 Dictionary<> 方式傳給前端的 AJAX (或插入 javascript 的變數),接著就來探討前端在接收到 Dictionary 物件後如何對應指定給網頁上的欄位(以 id 來對應)!
這篇續文拖了一個多月,因為在此期間另外被要求開發Android上的App (題庫模擬測驗,改天再發表成果),所以暫停了這個主題的實作。
不論從網頁Submit過來的資料,或由後端回傳的資料,我們都已用JSON格式轉化成字串,故此前端的Javascript必須解析此一字串的內容,雖然說寫程式要站在巨人的肩膀上,可是現成處理前端往後送的模組很多,例如:jForm,甚至jQuery內帶的功能都可以幫我們把欄位或表單打包來Post給後端程式,但是處理JSON 資料對表單欄位對應的模卻少見,最多的是表格(Grid)的處理,所以就自己動手寫一支! cmj.formRender.js 可以從我的 google.Docs 下載!
對照利用javascript實做 MVC 網頁(二)的說明,要供前端應用的JSON字串會長成這個樣子:
{"userid":{"value":"i123","style":"color:red;text-align:right;"}} (單一欄位時) 或

{"userid":{"value":"i123","style":"color:red;text-align:right;"},
"title":{"value":"科長","style":"color:red;text-align:right;"}} (多欄位時) 或

[{"value":"1","style":"color:red;text-align:right;","text":"選項一"},
{"value":"2","style":"color:blue;text-align:left;","text":"選項二","selected":"selected"}] (單欄多值時)
上列的字串要先經 JSON.parse() 轉換成 JavaScript 的物件,再傳給 cmj.formRender.js 的函數!

cmj.formRender.js 提供5個函數:
rendForm(formData) :  會利用欄位的 id 屬性,自動設定欄位的值(value 或  text 或 checked 或 selected)

而下方的四個函數則針對 Option, Radio, CheckBox 及 List 的操值,這些欄位有一個共同的特性:多個選項清單

rendOption(parentObj, targetData, addTo)
rendRadio(parentObj, targetData, addTo, itemsPerLine)
rendCheckbox(parentObj, targetData, addTo, itemsPerLine)
rendList(parentObj, targetData, listType, itemsPerLine, addTo)
    說明:
       parentObj $(SELECTOR) 找到的物件
        targetData: 即上面回傳經 JSON.parse() 後的物件
        addTo: 是否附加到現有的項目之下(或者要先清現有項目)
        itemsPerLine: 針對 checkbox, radio 橫向要顯示幾個項目。
        listType: 字串 checkbox, radio, ol, ul 表示要產製的項目類別,rendRadio/rendCheckbox 會呼叫此一函數
也就是說呼叫rendCheckbox(parentObj, targetData, addTo, itemsPerLine)
和呼叫
       rendList(parentObj, targetData, 'checkbox', itemsPerLine, addTo)
是一樣的!

透過上面的5個函數,幾乎可以處理頁面上欄位「值」的問題,至於其他特效或 Grid 就借用現成的模組了!

系列連結:
利用javascript實做 MVC網頁(一)
利用javascript實做 MVC網頁(二)