DNS篇(詳解DNS)

*文章來源:https://blog.egsec.cn/archives/601

*本文將主要說明:本文主要敘述什麼是DNS、域名的層級、DNS 解析過程、DNS的緩存時間、DNS 的記錄類型、DNS 報文結構、DNS劫持與HTTP劫持以及手動清理本地緩存的方法。

 

DNS屬於應用層。DNS即域名系統,其作用是將字符串域名解析成相對於的服務器IP地址,免除人們記憶IP地址的單調和苦惱,屬於為用戶排憂解難之舉,因此劃歸為應用層。DNS不屬於協議,它是域名解析。

 

什麼是DNS

DNS是 Domain Name System 的縮寫,也就是 域名解析系統,它的作用非常簡單,就是根據域名查出對應的 IP地址。

你可以把它想象成一本巨大的電話本,比如當你要訪問域名www.egsec.cn,首先要通過DNS查出它的IP地址是118.31.61.137。

域名層級

DNS 的解析過程中,需要對域名的層級有了解:

  • 根域名 :.root 或者 . ,通常是省略的
  • 頂級域名,如 .com,.cn 等
  • 次級域名,如 baidu.com 里的 baidu,這個是用戶可以進行註冊購買的
  • 主機域名,比如 baike.baidu.com 里的baike,這個是用戶可分配的 
主機名.次級域名.頂級域名.根域名
baike.baidu.com.root

DNS 解析過程

咱們以訪問 www.egsec.cn 這個域名為例,來看一看當你訪問 www.egsec.cn 時,會發生哪些事:

  1. 先查找本地 DNS 緩存(自己的電腦上),有則返回,沒有則進入下一步
  2. 查看本地 hosts 文件有沒有相應的映射記錄,有則返回,沒有則進入下一步
  3. 向本地 DNS 服務器(一般都是你的網絡接入服務器商提供,比如中國電信,中國移動)發送請求進行查詢,本地DNS服務器收到請求后,會先查下自己的緩存記錄,如果查到了直接返回就結束了,如果沒有查到,本地DNS服務器就會向DNS的根域名服務器發起查詢請求:請問老大, www.egsec.cn 的ip是啥?
  4. 根域名服務器收到請求后,看到這是個 .cn 的域名,就回信說:這個域名是由 .cn 老弟管理的,你去問他好了,這是.cn老弟的聯繫方式(ip1)。
  5. 本地 DNS 服務器接收到回信后,照着老大哥給的聯繫方式(ip1),馬上給 .cn 這個頂級域名服務器發起請求:請問 .cn 大大,www.egsec.cn 的ip 是啥?
  6. .cn 頂級域名服務器接收到請求后,看到這是 egsec.cn 的域名,就回信說:這個域名是 .egsec.cn 老弟管理的,你就去問他就行了,這是他的聯繫方式(ip2)
  7. 本地 DNS 服務器接收到回信后,按照前輩的指引(ip2),又向 .egsec.cn 這個權威域名服務器發起請求:請問 egsec.cn 大大,請問 www.egsec.cn 的ip是啥?
  8. egsec.cn 權威域名服務器接收到請求后,確認了是自己管理的域名,馬上查了下自己的小本本,把 www.egsec.cn 的ip告訴了 本地DNS服務器。
  9. 本地DNS服務器接收到回信后,非常地開心,這下總算拿到了www.egsec.cn的ip了,馬上把這個消息告訴了要求查詢的客戶(就是你的電腦)。由於這個過程比較漫長,本地DNS服務器為了節省時間,也為了盡量不去打擾各位老大哥,就把這個查詢結果偷偷地記在了自己的小本本上,方便下次有人來查詢時,可以快速回應。

總結起來就是三句話:

  • 從”根域名服務器”查到”頂級域名服務器”的NS記錄和A記錄(IP地址)
  • 從”頂級域名服務器”查到”次級域名服務器”的NS記錄和A記錄(IP地址)
  • 從”次級域名服務器”查出”主機名”的IP地址

DNS的緩存時間

上面的幾個步驟里,可以看到有兩個地方會緩存 DNS 的查詢記錄,有了緩存,在一定程度上會提高查詢效率,但同時在準確率上會有所損失。

因此我們在配置 DNS 解析的時候,會有一個 TTL 參數(Time To Live),意思就是這個緩存可以存活多長時間,過了這個時間,本地 DNS 就會刪除這條記錄,刪除了緩存后,你再訪問,就要重新走一遍上面的流程,獲取最新的地址。

DNS 的記錄類型

當我們在阿里雲買了一個域名后,可以配置我們主機域名解析規則,也就是 記錄。  

阿里雲域名雲解析(不管是哪個服務商都一樣):

常見的 DNS 記錄類型如下

  • A:地址記錄(Address),返回域名指向的IP地址。
  • NS:域名服務器記錄(Name Server),返回保存下一級域名信息的服務器地址。該記錄只能設置為域名,不能設置為IP地址。
  • MX:郵件記錄(Mail eXchange),返回接收电子郵件的服務器地址。
  • CNAME:規範名稱記錄(Canonical Name),返回另一個域名,即當前查詢的域名是另一個域名的跳轉,詳見下文。
  • PTR:逆向查詢記錄(Pointer Record),只用於從IP地址查詢域名,詳見下文。

DNS報文結構

  1. 事務 ID:DNS 報文的 ID 標識。對於請求報文和其對應的應答報文,該字段的值是相同的。通過它可以區分 DNS 應答報文是對哪個請求進行響應的。
  2. 標誌:DNS 報文中的標誌字段。
  3. 問題計數:DNS 查詢請求的數目。
  4. 回答資源記錄數:DNS 響應的數目。
  5. 權威名稱服務器計數:權威名稱服務器的數目。
  6. 附加資源記錄數:額外的記錄數目(權威名稱服務器對應 IP 地址的數目)

DNS劫持與HTTP劫持

通過上面的講解,我們都知道了,DNS 完成了一次域名到 IP 的映射查詢,當你在訪問 www.egsec.cn 時,能正確返回給你 我網站首頁的 ip。

但如果此時 DNS 解析出現了一些問題,當你想要訪問 www.egsec.cn 時,卻返回給你 www.baidu.com 的ip,這就是我們常說的 DNS 劫持。

與之容易混淆的有 HTTP 劫持。

什麼是 HTTP 劫持?

你一定見過當你在訪問 某個網站時,右下角也突然彈出了一個扎眼的廣告彈窗。這就是 HTTP 劫持。

藉助別人文章里的例子,它們倆的區別就好比是

  • DNS劫持是你想去機場的時候,把你給丟到火車站。
  • HTTP劫持是你去機場途中,有人給你塞小廣告。

DNS劫持 是如何產生的?

下面大概說幾種DNS劫持方法:

1.本機DNS劫持

攻擊者通過某些手段使用戶的計算機感染上木馬病毒,或者惡意軟件之後,惡意修改本地DNS配置,比如修改本地hosts文件,緩存等

2. 路由DNS劫持

很多用戶默認路由器的默認密碼,攻擊者可以侵入到路由管理員賬號中,修改路由器的默認配置

3.攻擊DNS服務器

直接攻擊DNS服務器,例如對DNS服務器進行DDOS攻擊,可以是DNS服務器宕機,出現異常請求,還可以利用某些手段感染dns服務器的緩存,使給用戶返回來的是惡意的ip地址

如何在本地查詢 DNS 解析結果?

nslookup命令:

命令格式:nslookup [查詢的域名] [指定DNS服務器]

你也可以指定公網的域名服務器進行查詢,比如常見的 114.114.114.114

手動清理DNS緩存

MacOS:

sudo dscacheutil -flushcache
$ sudo killall -HUP mDNSResponder

Windows:

$ ipconfig /flushdns

Linux:

使用NSCD的DNS緩存
$ sudo /etc/init.d/nscd restart

# 服務器或者路由器使用DNSMASQ
$ sudo dnsmasq restart

  

DNS詳解篇完

轉發請註明出處(EG Blog:blog.egsec.cn),謝謝!

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

世界最快螞蟻 步頻是波爾特10倍以上

摘錄自2019年10月17日自由時報報導

報導,德國烏爾姆大學(University of Ulm University)生物行為專家普費弗(Sarah Pfeffer)所率領的團隊,發現撒哈拉銀蟻是世界上最快的螞蟻,每秒秒速將近1公尺,看起來雖然不多,但驚人步頻(跑步時腳步交換的頻率)可是世界百米紀錄保持人波爾特(Usain Bolt)的10倍以上。

撒哈拉銀蟻可以用每秒47步跑完85.5公分,這距離達到了牠們體長的108倍之多,如果拿家貓的體型來比喻的話,撒哈拉銀蟻的速度大約是貓貓以時速193公里奔跑。這是因為牠們全速奔跑時,6隻腿會一起騰空再落地,看起來就像是在短暫飛行,在每次換步時,銀蟻每條腿的觸地時間不到7毫秒。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

「敢檢討核電海嘯對策就開除你喔!」 解析處處矛盾的福島核災判決

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

拯救漏油生態危機:菲律賓吉馬拉斯島的故事

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

2020-為什麼換了工作

摘要

經歷了一個特殊的2020上半年,疫情出乎意料的持續了半年之久,還是沒有看到結束的趨勢。雖然外部環境很惡劣,還是做出了個人的重大選擇,換工作。期間糾結了很久,畢竟工作就是生活,換工作就是對未來的期待,對過去的總結,對自己的人生的深度思考。這裏回顧下當時的個人思考,供後續復盤參考。

當前的狀況

2020,本科畢業的第六年,不再像剛畢業那會,覺得換公司是輕而易舉的事,考慮的事情越來越多。
畢業五年開始就越發的焦慮,這是當時的心境
2019年春-當前的困境、
2019秋-走的太久忘記了為什麼出發

總結起來

  1. 在擁抱變化的過程中,沒有匹配上自己的個人目標
  2. 工作多年還依然在糾結擅長和喜歡

老馬說的員工想要離職無非兩個原因

  1. 錢沒給到位
  2. 心委屈了
    分別是物質和精神方面。算是高度概括了。細分起來就是三方面錢、人、事。

錢的計算相對比較複雜了。

  1. 時薪和月薪
    月薪20K 的996,和15K的965相比,時薪還要低不少。但是如何選擇,每個人的情況不一樣,選擇不一樣
  2. 月薪和總包
    互聯網公司的總包除了現金部分還包括股票或者期權。一般分4年歸屬,待滿兩年才能拿到一半。股票的價值不好估算,畢竟二級市場波動很大。對比股票,期權價值就更不好估算了。因為沒上市的公司估值的水分很大,另外不一定能兌現,畢竟上市沒那麼容易。但是機會和風險並存,創業公司會給很多期權來吸引(忽悠)人才加入。你想獲得高額的回報甚至是財務自由,就得冒很大的風險。

所以總收入: 現金 + 風險係數 * 股票/期權價值。 同時考慮你的時間比。

那對於當前的我來說,缺錢,但是不是缺工作跳槽的錢。怎麼說呢,就是生活基本物質得到了保障,但是更高的需求無法滿足,而這些多出來的需求靠換工作是滿足不了。所以錢不是重點考慮的。

互聯網的從業人員的個人素質相對比較高,加上工作專業度比較高,所以都比較簡單,沒那麼多亂七八糟的人情世故需要去處理。所以相處起來還比較愉快。

但是人與人之間是有磁場的,不是每個人都能和你對脾氣、遇到合適的領導,相近的同事也沒那麼容易,另外建立關係也需要時間。這個對於跳槽是減分項。

事包含兩部分,一部分是成就感,一部分個人成長機會。也就是通常說的借人成事、借事修人。

馬斯洛需求理論最高層級就是自我實現。對於互聯網人,每天除了睡覺,70%以上時間都給了工作,那自我實現肯定要在工作中實現。

那對於我個人而已,相對穩定的業務,確定性比較高,沒什麼發展前景的就沒什麼吸引力。希望是有挑戰性的工作,能把事情做成功,並且自己能夠在其中發揮重要的作用。

個人成長其實就是未來。個人成長不是一蹴而就的,短期內不易覺察。但是非常重要,互聯網更新很快,你沒跟上就被淘汰了。對於廣泛流傳的程序員成長路線,3年高工,7年架構,10年外賣。

雖然是調侃,但是也說明了幾點內容

  1. 更新迭代很快的互聯網對大齡人不是很友好,你必須要持續成長。恍惚中我就工作6年,在互聯網行業中都算一個老兵了。
  2. 互聯網人的職業發展與其他行業發展曲線不一樣。一個發展很快,新知識很多的領域,個體是永遠追不上行業的發展水平的。

總結來說,發展是當前跳槽的主要考慮因素。

跳槽的期望

有了換工作的想法,是對現狀的不滿,但是換一個環境並不意味着問題的解決。這也是為什麼很多人經常抱怨公司的不好,但是不挪窩的原因。我們不能寄希望於未知的事情。尤其是從18年底開始互聯網整體再走下坡路,就業環境並不好,加上今年疫情的原因,外部環境更加惡化。

但是大環境不好,不代表個體就不好。不確定性很多不代表沒有確定性的東西。人的一生就是在不斷選擇中度過的,我們必須要了解自己,抓住重點,匹配自己與環境。

那麼我的個人期望是怎麼樣的,新的工作能滿足我的期望嗎?

職業發展

之前迷茫過還要不要做程序員,能不能轉行到產品,諮詢,售前。現在不能說篤定了一直做技術,但是找到了一些發展規律。

  1. 不會再去做偏底層的技術
    以前做過大數據,BI,甚至3年前還拿到過大數據工程師的offer,現在也深入了解了運維、中間件相關的工作內容。徹底打消了偏技術側的技術開發。
  2. 解決問題為驅動
    問題為導向,離業務越近越好。通過技術來驅動業務,非技術手段來解決業務問題。

這個算是近兩年個人的一個不小的突破,排除了哪些事不會去做,哪些事要去嘗試探索。

行業

行業涉及面太廣了,現在toC不好做,巨頭林立把用戶時間都擠佔了。toB 更難了,工具效率型的,國內目前付費意願並不強,能幫助企業帶來收入的才能發展的下去。

個人目前對具體做哪個行業的並沒有那麼執着。更多的期望是能夠以某個點切入到某個行業,然後看到如何通過互聯網技術把問題解決了,形成閉環,把事情做成功了。這種成就感足以讓我興奮。因為這些年,在不同的公司做各種創業項目,都沒有做成功的,都因為各種原因死掉了。正因如此,才知道創業是如何的艱難與不易。

通過自我的剖析和明確當前職業發展目標,在2020年春夏之際,我成功換了工作。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

Jmeter系列(32)- 詳解 CSV 數據文件設置

如果你想從頭學習Jmeter,可以看看這個系列的文章哦

https://www.cnblogs.com/poloyy/category/1746599.html

 

了解一哈什麼是 CSV 文件

  • 為了實現簡單的數據存儲,是一個純文本的文件
  • 最通用的一種文件格式,它可以非常容易地被導入各種PC表格及數據庫中
  • CSV 文件可以用記事本、excel打開;用記事本打開的話,每一列數據都用逗號隔開

 

為什麼要用 CSV 數據文件?

  • 從外部導入測試數據,相當於數據參數化
  • 通過從文件中導入大量的測試數據,來模擬大量真實用戶發送併發請求

 

CSV 數據文件設置

 

CSV 數據文件設置界面介紹

 

字段含義

字段 含義
Filename 文件名
File encoding 文件編碼
Variable Names
  • 變量名稱
  • 多個變量用 , 分隔
Ignore first line
  • 忽略首行
  • 只在設置了變量名稱后才生效
Delimiter
  • 分隔符
  • 默認 , 
Allow quoted data? 是否允許帶引號
Recycle on EOF? 遇到文件結束符EOF 后再次循環
Stop thread on EOF? 遇到文件結束符EOF 后停止運行線程?
Sharing mode 線程共享模式

後續通過各種栗子來深入理解常用字段的含義

 

單個字段的栗子

csv 測試數據

這裏用記事本方式當 CSV 數據文件,共有 10 條記錄

 

線程組結構樹

${num} 是計數器裏面聲明的變量,從 1 開始遞增到 15

 

線程組屬性

線程數和數據量一致,都是 15

 

csv 數據文件設置

 

運行結果

 

知識點

  • 忽略首行 True:一般首行都是字段名字,比如栗子的 mobile,一般都需要忽略除非沒有字段名
  • 是否允許帶引號 False:可以看到有引號的三條記錄 8、9、10,都還是保留了引號
  • 再次循環 True:csv 文件共有 10 條記錄,但線程數有 15 個,循環 10 次后,重頭開始循環;可以看到 11-15的手機號和1-5的手機號
  • 停止線程 False:取了 10 次值之後就到了文件尾部,但並不會停止運行線程,後面會舉個反例

 

多個字段的綜合栗子

csv 測試數據

兩個字段,共有 10 條記錄,最後三條記錄有分別有三種引號

 

csv 數據文件設置

線程組結構樹和上面栗子差不多一樣,線程數仍然 = 15

和第一個例子的配置項相反:不忽略首行,允許帶引號,遇到文件結束符不再循環

 

運行結果

  • 不忽略首行就會把首行的字段名都返回回來,如:1-mobile-age
  • 數據有雙引號 “” 時,會把雙引號忽略掉,  單引號不算
  • EOF 是文件結束符,沒有開啟再次循環時,會直接返回 EOF

 

開啟遇到文件結束符停止線程

還是上個栗子的線程組,只是改了下配置項

 

運行結果

可以看到,線程數 = 15,但只有 10 條數據,當跑了 10 個線程后,沒有數據了,所以停止運行

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

Python 偏函數用法全方位解析

Python的functools模塊中有一種函數叫“偏函數”,自從接觸它以來,發現確實是一個很有用且簡單的函數,相信你看完這篇文章,你也有相見恨晚的感覺。

我們都知道,函數入參可以設置默認值來簡化函數調用,而偏函數的作用就是將入參進行默認填充,降低函數使用的難度

如int()函數,可以將字符型轉換為整型,且默認的都是以十進制形式來轉換,那為什麼一定是十進制呢?如果想用以二進制的形式轉換呢?其實我們可以看一下int函數它本身的定義

可以看到int有兩種用法,可以傳一個位置參數,還可以多傳一個關鍵字參數base,也就是基於什麼格式轉換,默認不傳base參數是以十進制轉換。所以,用二進制形式轉換的話只要base=2即可(見下方代碼)

1 value = int('10000') 2 print(value)    # 10000
3 
4 value = int('10000', base=2) 5 print(value)    # 16

如果每次轉換的字符串的時候都要輸入base參數,顯得很麻煩,因此偏函數的作用就體現出來了,可以使用functools.partial()函數來重新定義

1 from functools import partial 2 
3 int2 = partial(int, base=2) 4 res = int2('10000') 5 print(res)     # 16

到這裏,你應該已經感覺到了偏函數的一點點魅力吧,那我們再從多個角度進一步看透它。

  • 自定義函數的使用
1 def add(a, b, c): 2     print('a=',a,'b=',b,'c=',c) 3     return a + b + c 4 
5 add10 = partial(add, 10) 6 res = add10(1, 2)     # a= 10 b= 1 c= 2

如上代碼中,partial(add, 10)入參並沒有指定哪個關鍵字參數,函數卻默認的將這個值傳給了第一個參數a,那就說明,當沒有指定默認參數時,默認賦值給第一個參數,餘下參數按位置參數賦值

  • 當入參為可變參數時
1 def sum(*args): 2     s = 0 3     for n in args: 4         s += n 5     return s 6 
7 sum10 = partial(sum, 10) 8 print(sum10(1))    # 11
9 print(sum10())     # 10

按上述理解,沒有指定默認參數時,默認賦給第一個參數,那麼第一個參數永遠是10,後面再傳入參的話就從第二個參數開始計算,因此會實現10 + 1 = 11 的結果。同樣,如果不繼續傳參的話,只有默認的10,所以結果就是10

  • 當入參為可變關鍵字參數時
 1 D = {'value1':10, 'value2':20}
 2 V = {'Default':100}
 3 def show(**kw):
 4     for k in kw:
 5         print(k, kw.get(k))
 6 
 7 showDef = partial(show, **V)    
 8 showDef(**D)   
 9 # Default 100
10 # value1 10
11 # value2 20

同理,此時入參由於是可變參數,因此默認是第一個傳入,先打印Default關鍵字,這裏關注一下函數的寫法,可變關鍵字參數要寫成(**V)

  • 當入參為限制的關鍵字參數時
1 def student(name, * , age, city): 2     print('name:',name, 'age:',age, 'city:',city) 3 
4 studentAge = partial(student, age=20) 5 studentAge('Tom','Beijing') 6 # TypeError: student() takes 1 positional argument but 2 positional arguments (and 1 keyword-only argument) were given

我們知道,當用*號分隔開,表示後面的關鍵字參數是必傳的,因此對於默認參數也是同樣適用,即當參數為必傳時,偏函數也需要對每個關鍵字參數設置默認值。因此修改後為

1 studentAge = partial(student, age=20, city='Beijing') 2 studentAge('Tom')  # name: Tom age: 20 city: Beijing

 

綜上,偏函數可以將目標函數的部分參數固化后,重新定義為新的函數,降低了編碼的複雜度,尤其是當參數很多的時候,或者只用到其中某些參數的場景下時,效果更為顯著。

到這裏,你是否有了相見恨晚的感覺呢?簡單函數小技巧,非常實用的偏函數用法就介紹完了,如果覺得有用,請關注我,後續會繼續分享更多好用好知識。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

這 10 行比較字符串相等的代碼給我整懵逼了,不信你也來看看|原創版

抱歉用這種標題吸引你點進來了,不過你不妨看完,看看能否讓你有所收穫。​(有收穫,請評論區留個言,沒收穫,下周末我直播吃**,哈哈,這你也信)

補充說明:微信公眾號改版,對各個號主影響還挺大的。目前從後台數據來看,對我影響不大,因為我這反正都是小號,閱讀量本身就少的可憐,真相了,狗頭(剛從交流群學會的表情)。

先直接上代碼:

boolean safeEqual(String a, String b) { if (a.length() != b.length()) { return false; } int equal = 0; for (int i = 0; i < a.length(); i++) { equal |= a.charAt(i) ^ b.charAt(i); } return equal == 0; } 

上面的代碼是我根據原版(Scala)翻譯成 Java的,Scala 版本(最開始吸引程序猿石頭注意力的代碼)如下:

def safeEqual(a: String, b: String) = { if (a.length != b.length) { false } else { var equal = 0 for (i <- Array.range(0, a.length)) { equal |= a(i) ^ b(i) } equal == 0 } } 

剛開始看到這段源碼感覺挺奇怪的,這個函數的功能是比較兩個字符串是否相等,首先“長度不等結果肯定不等,立即返回”這個很好理解。

再看看後面的,稍微動下腦筋,轉彎下也能明白這其中的門道:通過異或操作1^1=0, 1^0=1, 0^0=0,來比較每一位,如果每一位都相等的話,兩個字符串肯定相等,最後存儲累計異或值的變量equal必定為 0,否則為 1。

再細想一下呢?

for (i <- Array.range(0, a.length)) { if (a(i) ^ b(i) != 0) // or a(i) != b[i] return false } 

我們常常講性能優化,從效率角度上講,難道不是應該只要中途發現某一位的結果不同了(即為1)就可以立即返回兩個字符串不相等了嗎?(如上所示)

這其中肯定有……

再再細想一下呢?

結合方法名稱 safeEquals 可能知道些眉目,與安全有關。

本文開篇的代碼來自playframewok 里用來驗證cookie(session)中的數據是否合法(包含簽名的驗證),也是石頭寫這篇文章的由來。

以前知道通過延遲計算等手段來提高效率的手段,但這種已經算出結果卻延遲返回的,還是頭一回!

我們來看看,JDK 中也有類似的方法,如下代碼摘自 java.security.MessageDigest

public static boolean isEqual(byte[] digesta, byte[] digestb) { if (digesta == digestb) return true; if (digesta == null || digestb == null) { return false; } if (digesta.length != digestb.length) { return false; } int result = 0; // time-constant comparison for (int i = 0; i < digesta.length; i++) { result |= digesta[i] ^ digestb[i]; } return result == 0; } 

看註釋知道了,目的是為了用常量時間複雜度進行比較。

但這個計算過程耗費的時間不是常量有啥風險? (腦海里響起了背景音樂:“小朋友,你是否有很多問號?”)

真相大白

再深入探索和了解了一下,原來這麼做是為了防止計時攻擊(Timing Attack)。(也有人翻譯成時序攻擊​)​

計時攻擊(Timing Attack)

計時攻擊是邊信道攻擊(或稱”側信道攻擊”, Side Channel Attack, 簡稱SCA) 的一種,邊信道攻擊是一種針對軟件或硬件設計缺陷,走“歪門邪道”的一種攻擊方式。

這種攻擊方式是通過功耗、時序、電磁泄漏等方式達到破解目的。在很多物理隔絕的環境中,往往也能出奇制勝,這類新型攻擊的有效性遠高於傳統的密碼分析的數學方法(某百科上說的)。

這種手段可以讓調用 safeEquals("abcdefghijklmn", "xbcdefghijklmn") (只有首位不相同)和調用 safeEquals("abcdefghijklmn", "abcdefghijklmn") (兩個完全相同的字符串)的所耗費的時間一樣。防止通過大量的改變輸入並通過統計運行時間來暴力破解出要比較的字符串。

舉個,如果用之前說的“高效”的方式來實現的話。假設某個用戶設置了密碼為 password,通過從a到z(實際範圍可能更廣)不斷枚舉第一位,最終統計發現 p0000000 的運行時間比其他從任意a~z的都長(因為要到第二位才能發現不同,其他非 p 開頭的字符串第一位不同就直接返回了),這樣就能猜測出用戶密碼的第一位很可能是p了,然後再不斷一位一位迭代下去最終破解出用戶的密碼。

當然,以上是從理論角度分析,確實容易理解。但實際上好像通過統計運行時間總感覺不太靠譜,這個運行時間對環境太敏感了,比如網絡,內存,CPU負載等等都會影響。

但安全問題感覺更像是 “寧可信其有,不可信其無”。為了防止(特別是與簽名/密碼驗證等相關的操作)被 timing attack,目前各大語言都提供了相應的安全比較函數。各種軟件系統(例如 OpenSSL)、框架(例如 Play)的實現也都採用了這種方式。

例如 “世界上最好的編程語言”(粉絲較少,評論區應該打不起架來)—— php中的:

// Compares two strings using the same time whether they're equal or not. // This function should be used to mitigate timing attacks; // for instance, when testing crypt() password hashes. bool hash_equals ( string $known_string , string $user_string ) //This function is safe against timing attacks. boolean password_verify ( string $password , string $hash ) 

其實各種語言版本的實現方式都與上面的版本差不多,將兩個字符串每一位取出來異或(^)並用或(|)保存,最後通過判斷結果是否為 0 來確定兩個字符串是否相等。

如果剛開始沒有用 safeEquals 去實現,後續的版本還會通過打補丁的方式去修復這樣的安全隱患。

例如 JDK 1.6.0_17 中的Release Notes[1]中就提到了MessageDigest.isEqual 中的bug的修復,如下圖所示:

MessageDigest timing attack vulnerabilities

大家可以看看這次變更的的詳細信息openjdk中的 bug fix diff[2]為:

MessageDigest.isEqual計時攻擊

Timing Attack 真的可行嗎?

我覺得各大語言的 API 都用這種實現,肯定還是有道理的,理論上應該可以被利用的。 這不,學術界的這篇論文就宣稱用這種計時攻擊的方法破解了 OpenSSL 0.9.7 的RSA加密算法了。關於 RSA 算法的介紹可以看看之前本人寫的這篇文章。

這篇Remote Timing Attacks are Practical[3] 論文中指出(我大致翻譯下摘要,感興趣的同學可以通過文末鏈接去看原文):

計時攻擊往往用於攻擊一些性能較弱的計算設備,例如一些智能卡。我們通過實驗發現,也能用於攻擊普通的軟件系統。本文通過實驗證明,通過這種計時攻擊方式能夠攻破一個基於 OpenSSL 的 web 服務器的私鑰。結果證明計時攻擊用於進行網絡攻擊在實踐中可行的,因此各大安全系統需要抵禦這種風險。

最後,本人畢竟不是專研完全方向,以上描述是基於本人的理解,如果有不對的地方,還請大家留言指出來。感謝。

補充說明2:感謝正在閱讀文章的你,讓我還有動力繼續堅持更新原創。

本人發文不多,但希望寫的文章能達到的目的是:佔用你的閱讀時間,就盡量能夠讓你有所收穫。

如果你覺得我的文章有所幫助,還請你幫忙轉發分享,另外請別忘了點擊公眾號右上角加個星標,好讓你別錯過後續的精彩文章(微信改版了,或許我發的文章都不能推送到你那了)。

​原創真心不易,希望你能幫我個小忙唄,如果本文內容你覺得有所啟發,有所收穫,請幫忙點個“在看”唄,或者轉發分享讓更多的小夥伴看到。 ​ 參考資料:

  • Timing Attacks on RSA: Revealing Your Secrets through the Fourth Dimension
  • Remote Timing Attacks are Practical

參考資料

[1] Release Notes: http://www.oracle.com/technetwork/java/javase/6u17-141447.html

[2] openjdk中的 bug fix diff: http://hg.openjdk.java.net/jdk6/jdk6/jdk/rev/562da0baf70b

[3] Remote Timing Attacks are Practical: http://crypto.stanford.edu/~dabo/papers/ssl-timing.pdf

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

【JAVA8新的時間與日期 API】- 傳統時間格式化的線程安全問題

Java8之前的日期和時間API,存在一些問題,最重要的就是線程安全的問題。這些問題都在Java8中的日期和時間API中得到了解決,而且Java8中的日期和時間API更加強大。

傳統時間格式化的線程安全問題

示例:

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return sdf.parse("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }

     pool.shutdown(); } }

以上代碼運行會報錯:

 

 

報錯緣由:取部分源碼解釋

    /**
     * SimpleDateFormat 類的 parse 方法 部分源碼
     */
    public Date parse(String source) throws ParseException
    {
        ParsePosition pos = new ParsePosition(0);
        Date result = parse(source, pos); 
        if (pos.index == 0)
            throw new ParseException("Unparseable date: \"" + source + "\"" ,
                pos.errorIndex);
        return result;
    }

public Date parse(String text, ParsePosition pos)
    {
        // 省略上面諸多代碼
        Date parsedDate;

        CalendarBuilder calb = new CalendarBuilder();
        try {
            //這裏這個 calendar 對象是 SimpleDateFormat 類的父類 DateFormat 中的屬性  : protected Calendar calendar;
            parsedDate = calb.establish(calendar).getTime();//這個 calb.establish(calendar) 方法中,這個方法中的主要步驟不是原子操作,並且會對 calendar 對象進行修改,所以在多線程環境下就會出現線程安全問題。
            // 省略下面面諸多代碼
        }
        catch (IllegalArgumentException e) {
            //省略.........................
            return null;
        }
        return parsedDate;
    }
 Calendar establish(Calendar cal) {
        boolean weekDate = isSet(WEEK_YEAR)
                            && field[WEEK_YEAR] > field[YEAR];
        if (weekDate && !cal.isWeekDateSupported()) {
            // Use YEAR instead
            if (!isSet(YEAR)) {
                set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
            }
            weekDate = false;
        }

        cal.clear();
        // Set the fields from the min stamp to the max stamp so that
        // the field resolution works in the Calendar.
        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
            for (int index = 0; index <= maxFieldIndex; index++) {
                if (field[index] == stamp) {
                    cal.set(index, field[MAX_FIELD + index]);
                    break;
                }
            }
        }

        if (weekDate) {
            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
            int dayOfWeek = isSet(DAY_OF_WEEK) ?
                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
                if (dayOfWeek >= 8) {
                    dayOfWeek--;
                    weekOfYear += dayOfWeek / 7;
                    dayOfWeek = (dayOfWeek % 7) + 1;
                } else {
                    while (dayOfWeek <= 0) {
                        dayOfWeek += 7;
                        weekOfYear--;
                    }
                }
                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
            }
            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
        }
        return cal;
    }

綜上,我們可以看到 SimpleDateFormat 類中的parse 方法,調用了 CalendarBuilder 的 establish(calendar) 方法,並在方法中,對 calendar 對象進行了各種判斷及修改,並且這些操作都不是原子操作或同步操作,而這個calendar 對象又是 SimpleDateFormat 的父類 DateFormat 的一個實例變量,所以,在多線程同時調用SimpleDateFormat 的 parse 方法的時候,就會出現線程安全問題。


針對以上異常,JAVA8之前的解決辦法:

1. 將 SimpleDateFormat 對象定義成局部變量。

2. 加鎖。

3. 使用ThreadLocal,每個線程都擁有自己的SimpleDateFormat對象副本。

示例(加鎖):

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public synchronized Date call() throws Exception {//加個同步,解決問題
                return sdf.parse("2020-01-01");
//                return DateFormatThreadLocal.convert("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }
        pool.shutdown();

 

示例(ThreadLocal):

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatThreadLocal {
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    };
    public static Date convert(String source) throws Exception {
        return df.get().parse(source);
    }
}


////////////////////////////////////////////////////////////////

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
//                return sdf.parse("2020-01-01");
                return DateFormatThreadLocal.convert("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }
     pool.shutdown();
} }

 

JAVA8的解決辦法:使用新的API(DateTimeFormatter  和 LocalDate )

示例:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        Callable<LocalDate> task = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
//                return sdf.parse("2020-01-01");
                return LocalDate.parse("2020-01-01",formatter);
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<LocalDate>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<LocalDate> future = pool.submit(task);
            list.add(future);
        }
        for (Future<LocalDate> future : list){
            System.out.println(future.get());
        }
        pool.shutdown();
    }
}

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

中興通訊每年投逾50億 進軍新能源汽車

中國手機廠商中興通訊推出的自主研發的大功率無線充電系統,已進入公共交通領域。2014年10月,中興通訊攜手蜀都客車共同發佈全球首個無線充電城市微循環解決方案。該方案可以在不專門征地的情況下,在社區附近將任何現有停車位或路面直接改造為安全快捷的充電站。   “目前我們已經與10多個城市簽約,包括四川、河北、雲南、河南等省的城市,與當地政府就公共汽車的無線充電進行合作。”中興通訊副總裁孫枕戈稱,下一步將會把無線充電落實到私家車領域。據孫枕戈介紹,今後新能源汽車有可能將以PPP(政府與私人組織之間合作建設城市基礎設施專案)模式進行運營,而且將獲得中央政府和地方政府的補貼。   孫枕戈表示,從2015年開始,中興通訊每年將投入至少10億元人民幣(約合新臺幣50.6億)進行無線充電設施的商業運作。中興通訊未來的戰略是將通訊技術與各行各業相連,即M-ICT戰略,無線充電項目是其中的一項,該項目是中興與大專院校、研究機構共同合作的結果。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?