2021年7月5日 星期一

周末讀書會:時間真的等於金錢???

enter image description here
我正在讀一本奇書,裡面有個觀念頗有意思。但在分享之前,我先問你一個問題…

你覺得…過去一年,哪一段時間你的生產力最高?
那段時間會不會正好是你最忙的時候?

其實並不一定,對不對? 也就是說,你可能很忙,但完全沒產出甚麼有價值的成果(俗話說是「瞎忙」),也可能實際工時很少,但成果豐碩(特別是創作者)。

書中有一個章節告訴我們,如果想提高生產力,你必須減少工作時數(注意,不是增加)。作者覺得,傳統的時間管理很有問題,因為工作時數不等於生產力。這部分你可能跟我一樣,我始終覺得,企業用工時來計算薪資(或是專案成本)是件很奇怪的事情。老闆想要(買)的到底是"成果"? 還是想要 “看到我在辦公室出現”?

這是大家都知道的道理,但如今這個持續了那麼久,讓我們覺得不可思議的薪資和成本設計,是過去一百年來延續出的結果(這邊我要提到另一本過去介紹過的書『組織再進化』,有空可以自己去看看)。你知道,過去(工業革命時代),“時間就是金錢”,那時候生產線林立,勞工的上班時間就100%等於產出時間,下了班離開了工廠、沒了生產設備就什麼事都不能做(也就是沒有產出)。

因此,在那個時代,工時=薪資(或成本)是很有道理的。但,這已經是將近一百年前的事情了,想想好玩,如今我們的勞基法的基本精神卻還是基於那個年代?

而今天,對我們(特別是開發、創作人員來說),工時跟生產力之間根本沒有必然的關係。你一定有這種經驗,有時候你靈思泉湧、創作如同神來之筆,半小時內可以完成平時三四倍的工作量。而另一些時間,你可能沒睡飽或因為私事思緒混亂,這時就算在辦公室待上一整天也做不完任何一件事情。

所以這本書的作者認為,“時間” 根本並不重要,專注力與精力才是重點。(好啦,他其實沒這麼說,他覺得時間也很重要,但不是唯一重要)

同時,他還做了一個有趣的實驗,實驗結果顯示,當工時加倍,其實最終的有效工作產出只比工時減半時增加了 “一點點”。但有趣的部份是,當事人總會 “以為” 自己的產出很高(因為感覺自己很忙),但統計之後則是發現 “根本沒有”。

我覺得這也解釋了,為何辦公室中許多主管很喜歡一直開會,因為開會會讓自己主觀上覺得一直很忙、一直有產出,但其實…你知道的,根本沒有。

所以,總的來說。

  1. 工時越長,並不代表工作成果(或產出)會越好
  2. 傳統時間管理很有問題,因為重要的(你想要的)根本不是時間
  3. 重點在於怎麼使用自己專注力最佳、精力最高的那段時間來工作

至於怎麼做,你可以看書,書裡面有講,我就不多說了。


WFH時代,我根本不在乎同仁工時有多少,因為,我想要的是成果,不是想花錢買員工出現在我面前的時數。

最有生產力的一年 (電子書)

2021年6月12日 星期六

讓Microsoft 365(Teams)的身分驗證支援2FA(Two-Factor Authentication)

enter image description here
前面說過,最近因為WFH的關係,協助了一些公司將許多地端的OA相關應用移動到像是Microsoft 365、teams、與Azure等雲端環境上,以確保萬一封城或是台灣大規模分區停電下,企業主要服務依舊可以透過雲端來存取和運行。也因為如此,上次和大家分享了如何在家裡透過VPN連上Azure,以安全的方式來存取雲端資源。

但除了讓用戶走VPN去存取雲端資源,以避免讓雲端上的資料或服務公開在網際網路上(讓駭客當箭靶),另外一個非常基本卻重要的機制,是使用M365/Teams/Azure等雲端服務的企業不該忽略的,也就是2FA(Two-Factor Authentication)。

很多企業用戶可能根本不知道,瀏覽器上常見的登入行為,本身就有機會造成資安疑慮的最大風險,只要用戶在不熟悉的電腦上登入(例如網咖、公用電腦、別人的筆電…)或是用了不熟悉的網路(像是車站、咖啡廳、或是網路上隨意搜尋到的免費WIFI分享網路),都很可能在無意之間讓你的帳密外洩。

由於Azure和Microsoft 365(包含MS Teams)都是攤在網際網路上的服務,倘若用戶一不小心帳密外洩,那造成的風險恐怕也是不低的。

如何讓帳密更安全嚴謹的使用呢? 答案就是2FA(Two-Factor Authentication),關於2FA的細節你很容易在網路上找到,這邊就不多提了,總之微軟除了讓用戶以帳密登入以外,還提供你多重的身分驗證機制,例如手機簡訊就是其中之一。

簡單的說,你可以將M365或是Azure帳密設定為 – 在陌生的電腦上登入時,即便正確輸入帳密,還得再透過手機簡訊進行2次驗證(也可以用App進行驗證)。如此一來,可以大幅增加駭客的攻擊難度,避免你在密碼不小心外洩(或被猜對)時,遭受到駭客的入侵。

讓admin開放此功能

設定的方式很簡單,首先,你必須讓M365(Teams)管理員幫你從後台開起這個功能,它位於M365的admin center–>設定–>組織設定–>多重要素驗證:
enter image description here

admin可以透過底下UI找到要開啟此功能的用戶,並且點選『啟用』即可:
enter image description here

你會看到底下畫面:
enter image description here

用戶設定2FA驗證(以手機簡訊為例)

啟用之後,下次該用戶成功登入後,就會發信自己被引導到底下畫面:
enter image description here

進入下一步之後,系統會讓你選擇第二重驗證方式:
enter image description here

你可以選擇行動電話驗證,輸入號碼並選擇使用簡訊驗證之後,按下『下一步』即可:
enter image description here
這時候,微軟會傳簡訊到你輸入的手機號碼上,請把簡訊中的數字輸入上圖畫面,並點選『驗證』鈕。

這時其實已經大致設定完畢,最後會出現底下畫面:
enter image description here
這是為了讓目前尚不支援2FA的環境可以有替代方案,直接點選上圖完成即口。

登入時

設定好之後,用戶的登入其實完全一樣,在都登入時的第一個畫面,都必須輸入帳號密碼:
enter image description here
但不同的是,當成功登入之後,若該電腦(設備)是第一次登入,則會跳出底下畫面:
enter image description here
這時快查看你的手機,你會發現手機上收到MS傳來的簡訊,其中包含六位數字代碼,請正確的輸入該六位數字代碼後,你才會獲得登入。

透過這樣的方式,你可以更安全的使用雲端的服務,即便萬一不小心密碼被猜中,你還有第二道防線"手機簡訊",可以保護你的身分不致外洩。雖然很容易,但企業內卻有許多用戶沒有做這樣的設定。趁著WFH,快鼓勵企業用戶為自己的資安加上第二道鎖吧。

2021年6月8日 星期二

WFH必備-在家中透過VPN使用Azure雲端上的服務

在一般的承平時期,企業內部網路要連接到位於雲端的服務,可能會採用 site to site VPN的形式,也就是把企業內網與Azure雲端的虛擬網路透過VPN互聯,達到安全連線的效果:
enter image description here

需求

但最近這幾周,很多企業開始居家上班(WFH),導致用戶需要從家裡存取雲端上的服務,不管是伺服器、網站、資料庫、或是檔案系統…這時候,該怎麼辦呢?

你可能會說,這很容易啊,位於azure上公有雲的服務,都有對外(對internet)的IP,只要開放讓同仁從家裡連線不就得了? 當然不行,因為如此一來,等於把企業的應用攤在網際網路上讓駭客當箭靶練習入侵,因此,我們還是必須走一個安全的方式才行。

做法有兩種,一個是在企業的防火牆上,開放用戶透過VPN從家裡連線的管道,讓用戶先從家裡連到公司,再從公司透過VPN存取雲端的服務。但這樣等於是透過企業機房作為橋接,大部分公司我猜也是這麼做,但有個小缺點,如果台灣斷電(別跟我說不可能),那所有的服務就只能停擺了,即便根本沒受影響的雲端服務也是。

因此,另一種作法呢,則是直接讓用戶從家裡以VPN連線到 Azure 雲端服務,直接存取企業在Azure雲端上的資源,如果你根本把整個企業機房(或上面的主要服務)都移上雲端上(做異地備援或主要服務),更適合這麼作:
enter image description here
這篇文章要介紹的,就是上面這個模式。

如何讓員工,直接透過VPN,從家裡(其實從公司也行)透過網際網路安全的連線到企業位於公有雲上的資源。

環境說明

好,為了說明這個情境,我們建立了一個簡單的模擬。請再仔細看一下上面這張圖,其中有幾個需要注意的部分:

  1. 假設企業在雲端有兩台VM(提供了企業的主要應用,先別管是DB還是AP是WEB…反正就是個情境),IP位置分別是10.0.0.4, 10.0.0.5,這兩台VM使用同一個虛擬網路,其子網路是10.0.0.0/24,這個虛擬網路就是待會我們要讓員工從家裡連上的虛擬網路。
  2. 為了讓員工從家裡安全的連上虛擬網路,我們有設置了一個Virtual Network Gateway,員工要從家裡連上虛擬網路,必須通過這個Virtual Network Gateway。
  3. 從家裡連上Virtual Network Gateway的工具,是Azure VPN Client,而我們用的驗證方式,是採用Azure AD 驗證,這意味著你必須要有一個AAD(放心,只要你用了Azure表示你一定有)。

好,有了上面的概念之後,就開始實作了。
由於我們的情境下,雲端環境上有兩台VM,我們規劃的位置是10.0.0.x,因此,我們會先建立一個虛擬網路(10.0.0.0/16),並且指定子網路為(10.0.0.0/24):
enter image description here

然後再在建立VM的時候,幫VM指定使用這個虛擬網路:
enter image description here
如此一來,建立出來的VM就會在該虛擬網路的子網路IP區段中。

如果你建立多台VM,你會發現這幾台VM可以用內部IP互通:
enter image description here

同時在v-net中也可以看到:
enter image description here

建立gateway

基本環境沒問題之後,請參考下圖,接下來我們要建立virtual network gateway的部分:
enter image description here

Virtual Network Gateway的建立採預設參數即可,但需要留意,建立的時候『虛擬網路』的部分必須選擇上面包含我們VM的這個虛擬網路(這理所當然),建立好之後,請點選Virtual Network Gateway的『點對站(P2S)設定』:

enter image description here

其中有幾個關鍵,首先,你知道的,當外部的用戶透過家裡(或網咖、或公司)連入我們在Azure雲端上的虛擬網路時,必須走VPN,因此也理當有個安全的身分驗證方式,因此我們在上面選擇了Azure AD作為身分驗證方式(上圖B),所以你會發現下方C、D、E的部分,就是為了設定AAD的相關資訊,其中被霧化的是AAD的租用戶ID,這個資訊你可以從你的AAD管理頁面中找到:
enter image description here

你會發現下圖中的D,有一個GUID,這是Azure AD 企業應用程式的ID,一般Public Azure我們用41b23e61-6c1e-4545-b367-cd054e0ed4b4。這部分的細節可以參考微軟官網: 建立 P2S VPN 連線的 Azure AD 租使用者: Azure AD 驗證 - Azure VPN Gateway | Microsoft Docs

enter image description here

設定好並且儲存了之後,請別忘記點選上圖F中的連結,他會跳出一個視窗要你登入(請用具有AAD管理員身分的帳號登入),他會引導你同意應用程式授權,這個動作是讓該應用程式具有使用你AAD部分資訊的權利。(等於是我們在AAD上安裝了個應用程式,如下圖…)
enter image description here
有沒有,上圖就是AAD中安裝了的那個應用程式(Azure VPN)。其實也就是為你提供VPN 驗證服務的伺服器端啦。

設定用戶端

好,有了這些之後,我們要來設定Client,也就是能讓同仁從家裡(其實公司也行)以AAD帳密Azure雲端虛擬網路的用戶端機制。

請點選上方的下載VPN用戶端,這個動作會花幾分鐘,請耐心等候:
enter image description here

你會下載到一個檔案,解壓縮後,會看到AzureVPN資料夾下,有一個xml文件:
enter image description here

他是一個組態檔,讓你可以從windows 10以VPN方式連入雲端,主要是提供給Azure VPN 用戶端這個程式用的:
enter image description here

如果你沒有上面這個程式,請從 windows 市集下載(位於: 取得 Azure VPN 用戶端 - Microsoft Store zh-TW )。下載完之後,把組態檔匯入即可。

但別急,你要正確地使用該應用程式,還必須做一個設定。

請參考底下微軟官網上的文件,設定P2S的憑證:
產生和匯出 P2S 的憑證: PowerShell - Azure VPN Gateway | Microsoft Docs

你可以直接透過powershell執行底下這兩段code:

$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject "CN=P2SRootCert" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign

New-SelfSignedCertificate -Type Custom -DnsName P2SChildCert -KeySpec Signature ` -Subject "CN=P2SChildCert" -KeyExportPolicy Exportable ` -HashAlgorithm sha256 -KeyLength  2048 ` -CertStoreLocation "Cert:\CurrentUser\My" ` -Signer $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2")

他將會幫你在用戶端建立憑證。

完成後,開啟 Azure VPN Client,將剛才的.xml設定檔匯入:
enter image description here

你會發現相關的設定資訊其實跟剛才我們在gateway上建立的差不多:
enter image description here

完成後,你就有個可以直接連上Azure雲端虛擬網路的VPN可以用了:
enter image description here

透過上面這個設定,我們可以輕鬆的以VPN連入雲端,以內部IP的方式,啟動VM的遠端桌面連線:
enter image description here

當然不只是VM,上面只是透過VM來示範,而DB、AP Server或其他服務也是一樣的。當這樣的機制設定好之後,我們等同可以從家裏或公司,以VPN方式,安全的連入位於公有雲的雲端上的服務和應用、伺服器,而不需要把這些服務或伺服器攤在網際網路上當箭靶。是一個更適合企業在WFH階段使用雲端服務更好的方式。

2021年4月20日 星期二

如何在CI CD Pipeline中發送LINE通知訊息?

『如何在CI/CD Pipeline中發送LINE通知訊息?』有次,Azure DevOps上課時學員問了這個問題。

我聽到之後忍不住說:『這位同學你問得太好了!!!』
耐不住心中竊喜,繼續說道:『本人剛好有30秒可達成的全球最佳解決方案。😁』

要知道,關於LINE和Azure DevOps這兩個主題,分開來討論時我也向來是不落人後的,現在這兩個主題合在一起,那我當然就更不客氣了。

開啟Pipeline,我說『請看,第一個步驟,在pipeline中,加入『Use .net core』task:
enter image description here

接著,第二步,上LINE Notify官網,建立一個發訊息給你自己(或群組)的LINE Notify Token:
enter image description here

你會取得一個長得像底下這樣的token:
3QrpcH5XauJVoFCoSxbuWJH747TkC7yW5aXfsDk7RsM

然後,第三步驟,在Pipeline中,加入一個PowerShell Task,在inline script中填入底下指令:

dotnet tool install --global line.cli 
line notify -n 3QrpcH5XauJVoFCoSxbuWJH747TxC7yW5aXfsDk7RsM -m "$(Build.BuildNumber) is done. 狀態: $(Agent.JobStatus)"

enter image description here
然後? 然後就完成了。

現在,你可以自由的在上面這段script中發送訊息給自己(或自己的群組),當然還可以帶入環境變數$(…)。如此一來,每當CI build完成之後,不管成功或失敗,你都可以即時地取得通知,例如:
enter image description here

這一招,我們採用的是跨平台的 .net core,因此,不管你的build agent是MAC、Linux、還是Windows通通都支援啦😎。


相關課程:

敏捷開發專案管理與Azure DevOps實戰
https://www.studyhost.tw/NewCourses/ALM

LINE Bot與人工智慧實戰
https://www.studyhost.tw/NewCourses/LineBot

2021年4月17日 星期六

透過持續改善縮短你的cycle time

底下這張圖,看起來頗有學問…
圖片來自MS Azure DevOps AZ-400-1
圖片來自MS Azure DevOps AZ-400-1

我們在上DevOps的課程時,第一件事就問同學:在這個大企業林立、變化迅速的時代,新創或台灣的小公司在充滿資源的全球大企業輾壓下,要如何存活?

John Boyd的OODA循環帶給我們一個契機,如果你有興趣,可以google一下OODA循環,在wiki百科中的描述如下:

OODA循環的理論,來自於美國空軍在韓戰中的經驗。 在韓戰中擔任戰鬥機飛行員的空軍上校約翰·博伊德(John Boyd)認為,美國空軍過於注重速度,在越戰的早期空戰中,這一點就已凸顯出來。而與之形成鮮明對比的是,過時的蘇聯製米格戰鬥機卻在戰場上如魚得水,原因是因為米格機相對容易操作。 在對於競爭型戰鬥機進行了一番詳細分析之後,博伊德的結論是,飛機在空戰中最關鍵的性能並非絕對速度,而是敏捷度。在混戰中反應能力最強的戰鬥機能夠繞到敵人身後,隨時準備置敵於死地。 博伊德將其想法總結形成「OODA理論」。

在如今真實世界的挑戰中也是,最關鍵的性能並非『絕對速度』,而是『敏捷度』。這是新創和科技公司在最近這20年屢屢戰勝的核心原因。即便大公司擁有更多的資源,但面對挑戰總是輸在自身遲緩的反應上…

因此,DevOps的核心工作,其實是『持續改善,並竭盡所能的縮短你的循環時間(Shorten your cycle time)』。

這些cycle time包含…你修復一個Bug所需要的時間(改善一個錯誤的時間)、你增加一個新功能所需要的時間(在市場上提供新服務的時間)、學習並應用一們新的技術所需要的時間…

而這些縮短且省下的時間,就是你持續改善的所得到的『價值(Value)』,也是企業贏的關鍵。你的『持續改善』(持續縮小cycle time)最終停留在哪一點,你企業(或個人)的限制(瓶頸)就在哪一點出現。
圖片來自MS Azure DevOps AZ-400-1
圖片來自MS Azure DevOps AZ-400-1

因此,DevOps追求的是持續改善、持續整合,透過不斷合併與測試,盡早發現缺陷,盡早改善,就是DevOps中CI(continuous integration)做的事情。

面對縮短cycle time的挑戰…

  • 你能多快修復一個bug?
  • 你能多快上版(當然得同時兼顧安全性與品質)?
  • 新功能能夠多快交付到用戶手上?
  • 新構想能夠多快在市場上開始實驗?

改善的瓶頸,決定了企業的瓶頸。持續改善,能讓你的進步與競爭力能夠持續延續…


相關課程:
https://www.studyhost.tw/NewCourses/ALM

2021年3月20日 星期六

asp.net 身分驗證類型與基本原理(一)

這一篇很特別,我們要來談談 asp.net (.net core) 的身分驗證類型與基本原理(架構)。

最近這幾年,你可以從網站上找到任何你想找的資訊,特別是程式碼片段,但我總是眼睜睜的看著學員或客戶,從莫名的網路上抄來一份代碼,試著崁入自己的程式,無奈就是怎麼塞都塞不進去,不然就是硬塞進去之後,運行起來不如預期。

原因很簡單,因為硬Copy過來別人寫的東西,我們往往可能根本不知道那段程式碼寫的是什麼,只能硬插,無從改起。

這種狀況這幾年看了不少,身分驗證的部分更加明顯,有同學在寫WebAPI,但卻想用登入畫面去驗證呼叫者身分(!?),有人明明在寫MVC,卻一直在研究怎麼用JWT Token登入…細問同學為什麼要這麼做? 答案總是很有意思。

所以,一直想寫篇文章,來釐清一下這些東西。

asp.net 網站的身分驗證(保存)類型

asp.net 不管是哪一個版本,不管是 .net framework 或是 .net core,本質上都是一樣的。大部分情境下(這世界總有特例,文章也總是有背景,我們討論的是『大部分』情境下,若有特例,請讀者自行轉換),伺服器端保留(維持、識別) 用戶身分的機制大概有底下幾種:

  1. asp.net的Session變數
  2. aps.net Cookies 驗證
  3. Token (最近好像很流行 JWT)

首先,你必須知道一個前提,所有的Web應用程式和網路上伺服器和用戶端(瀏覽器)之間的交互(資料傳遞、呼叫)行為,本質上都是無狀態的(stateless),也就是說,你不能假設伺服器端知道用戶是誰,或是伺服器端連續兩次的呼叫是不是由同一位用戶觸發的。

enter image description here

這點跟你的經驗可能不符,你會覺得,網站(伺服器端)知道你是誰啊?不然用戶幹嘛登入? 登入後伺服器端不就知道用戶是誰了嗎?

對,許多的網站都能夠登入,如果是無狀態,那登入怎麼實現的?

好,實現的方式大多是底下這樣,在伺服器端與用戶端溝通(互動)的過程中,會在 http message(大多是header)中,夾帶著一個記號,這個記號具有唯一性,每一個用戶都不同,這個記號隨著網頁每次的來回傳遞(或是WebAPI的被呼叫),被夾帶在訊息(http message)之間,因此可以讓伺服器端知道當前的用戶端是哪一位。(這個記號大多只是一組ID,用來讓伺服器端識別用戶端,而非在記號中直接存放用戶名稱)
enter image description here

不管你用前述三種的哪一種身分保存方式,本質上最終都有這樣的一個機制存在。而預設狀況下,要實現這樣的結果,最方便的實作就是Cookies。

所以,即便你用伺服器端Session保存資訊,預設狀況下,也會用到Cookies,作為伺服器端與用戶端之間的關聯(associate),否則伺服器端根本不知道這Session是屬於哪一個用戶的。

參考: https://stackoverflow.com/questions/2589823/do-session-use-cookies

使用Session保留用戶身分

好,那我們先來談Session。
就如同我們大家所知,asp.net 的Session變數是存放在伺服器端,可以在單一Domain & 單一用戶的狀況下,進行跨頁面存取。(Session可以跨頁面、但不能跨網站、不能跨用戶)

所以,古時候很多網站的身分保存機制,是製作一個有帳密輸入功能的登入網頁,當用戶輸入帳密後按下登入,成功驗證帳號密碼與資料庫中保存的相符之後,就把用戶的帳號(或email)存在某個Session變數中,然後就視為該用戶已經登入完畢,且由於該Session變數可以跨網頁存取,因此在頁面巡覽(切換,跳頁)的過程中,只要該Session沒有過期(Timeout),後端都可以將前端該用戶視為已登入,並取得該用戶的身分(email或帳號)。

在這種模式底下,檢查用戶身分的方法,就是在網頁的後端程式碼中檢查保存用戶身分的Session變數內的值,如果有值,則表示已登入,並可取得用戶身分。

但別忘了,這狀態可以work,骨子裡還是因為用到了Cookies。

最近我們不建議用Session作為身分驗證方式,因為難以實現附載平衡或是高可用性,Session實質上是儲存在伺服器端的記憶體中的,當伺服器端有多台伺服器時,不容易跨伺服器保存。雖然可以採用資料庫作為Session的儲存位置,並實現跨伺服器(Web Server)使用Session,但如此一來用Session的意義就不大了。(因為犧牲了速度,最終跟使用Cookies可能差不了多少)

使用Cookies驗證

asp.net 本來就有一個 Cookies 驗證(cookies authentication)機制,這個機制本質上背後的作法跟前面我們一開始說的模式也差不多,就是在伺服器端(Server)與用戶端(Browser)溝通的過程中,保留一個具有唯一性(unique)的 State Cookie,並且把這個狀態Cookie在每一次瀏覽器的呼叫(post/get/…)過程中,傳遞給伺服器端。這樣伺服器端就可以知道用戶是同一個,然後伺服器端把資料或HTML回傳給用戶端的時候,也把Cookie回傳給用戶端。所以,你會看到,asp.net的http訊息當中,常常會看到底下這段:
enter image description here

因此,你會看到實作了 cookies 驗證的 asp.net core 網站,在http訊息中會夾帶著上面這樣的『記號』。透過這個唯一值,伺服器端就可以得知用戶端的身分了。而這一整段是由 asp.net 框架自動完成,所以開發人員大多不用寫什麼Code,可以直接用 user.identity.name 取得登入者是誰,用戶的登入與登出也大多只需要一兩行程式碼就可以搞定,使用起來非常方便。

有興趣可以參考筆者的 github 上 .net core 的範例:
https://github.com/isdaviddong/dotnetCore-PureWebAppLogin
文章:
https://studyhost.blogspot.com/2021/03/cookieswebapi_1.html

安不安全?

到這邊我們先岔題一下,待會再來談 Token。

先說,Session有沒有比較安全? 因為很多人一開始以為 Session是完全儲存在伺服器端的,所以一定比較安全! 但事實是,Session 必須倚賴傳遞於用戶端與伺服器端之間的 Cookies,因此結果最後跟使用Cookies驗證的安全性大致差不了太多。

再來,Cookies是否容易被惡意複製或竊取? 答案是,不無可能,但有難度

我們擔心 Cookies 被複製的主要原因,是擔心用戶身分被他人偽造(冒用)。要討論這個,重點在,這個他人是誰? 他在哪裡? (為何這重要? 待會你就知道)

主要有兩種可能:
1.在網際網路(或區域網路)上
2.在你的電腦上

先討論在網際網路上,有沒有人能夠在網路上偷看或竊取你的Cookies 資料? 這部分有個關鍵,就是傳遞的過程中有沒有走 SSL 加密,也就是 https 的protocal,如果沒有,那你的傳遞資料基本上是透明的,網路上人人可看,也就沒有安全性可言。如果你的傳輸過程是走 https ,那『理論上』,只有『瀏覽器』和『伺服器』兩端可以『看懂』你的資料,路上的其它人(駭客、設備、路由器、網路線、分享器…)看到了也看不懂,不容易竄改或偽造。

再講另一種Cookies被複製或竊取、偽造的可能位置,就是『在你的電腦上』。倘若,Cookies最終被儲存到電腦上的某個位置(硬碟),那當然還是有被複製(或竊取)的可能。只是,這個可能性有多高? 而且哪邊是可能的漏洞?

要知到,所有的資訊都可能存在於幾個位置,像是記憶體、畫面、硬碟…記憶體內的資料相對難被竊取(因為大部分的應用程式有獨立的行程,不能共享記憶體)、螢幕上的東西只要拿手機拍照就好(沒事不要把機密資料攤在螢幕上)、硬碟內的東西也相對容易被偷(應用程式有機會可以讀取到別的應用程式儲存的檔案或資料),所以有些公司崇尚『資訊不落地』,敏感的東西不得隨意儲存,只能在記憶體內使用。所以Chrome瀏覽器的無痕模式,會在關閉後清除所有Cookies。

但其實,上述Cookies最有可能的漏洞的確是『瀏覽器』,因為網路傳輸的過程中,只有瀏覽器碰到該資料(其它過程都有SSL保護),使用無痕瀏覽器時,關閉了視窗Cookies也被清除,但倘若瀏覽器本身有問題(來路不明、或被瀏覽器外掛給駭了),那當然就沒啥安全性可言。

所以,亂裝瀏覽器外掛其實很危險。另外,瀏覽器是透過OS(作業系統)運行,如果作業系統本身被駭了,那當然也有極高的安全性疑慮,因為控制了作業系統就控制了一切,隨時可以偷看你的記憶體或硬碟。所以,所有的作業系統安全性更新,都應該第一時間安裝。

所以結論是,如果走 https 的網站,在使用安全無虞的瀏覽器,且作業系統也沒安全性疑慮的狀況下,cookies應當是安全且不易被『非法』複製的。

框一個非法,因為用戶還是可以合法地去檢視和複製cookies。

總的來說,如果你的瀏覽器有問題,或是作業系統有問題。那沒什麼好說的,任何上網或其他運作都有風險疑慮。所以資安的第一個前提,就是不能讓駭客以任何方式接觸到實體設備,如果不能確保這個,那沒任何資安可言。

但如果瀏覽器可以被信任(不是雜牌瀏覽器),又都走https通訊,用戶也謹慎的使用無痕瀏覽模式,那安全性算是相當高的。

公用電腦上使用瀏覽器,一定要使用無痕視窗

什麼是 token

接著我們談 token,你常常聽到的 JWT就是token的一種。token,翻成中文比較好的翻譯是『令牌』,古時候武裝劇裡面的『見令如見人』的那種令牌。

拿著令牌,多半意味著可以存取些什麼資源。因此,大多數Token的運作行為(發放和使用)類似底下這樣。

  1. 由管理資源的單位(網站或系統, 例如管Google Drive的Google)發一個Token
  2. 這個Token代表著某個用戶授予的某種授權(例如David授予某人或某系統存取David的Google Drive中的文件的權限)
  3. 因此發token時,Google必須經過該用戶確認(所以David必須輸入Google帳密,當然是在Google的網站上,帳密也無須給他人知道,一般這類Token中也不會包含帳密或email)
  4. token發出後,可以交給某個系統(或某人)
  5. 得到該Token的人(或系統),就可以拿著這個token,向管理資源的單位(例如Google)取得用戶授予的某些資料(就是有存取該用戶 Google Docs的權限)

enter image description here
Token最典型的用法是上面這樣。反正就是個『令牌』的概念。

第三方網站(或是App),在需要存取用戶的Google Drive時,就是依照上面的流程,引導用戶去Google網站完成驗證(輸入帳密,同意授予權限),待取得Google發送的Token(令牌),第三方網站(或App)拿著這個令牌,就有權限去Google網站(一般是透過呼叫API的方式)以用戶授予的權限做些(或取得些)什麼。整個流程就是這樣。

Token的使用場合?

因此,token大多是用來證明自己(應用程式、呼叫端、第三方網站)具有存取某些資源的權限。你常會看到,用戶使用某個App的時候,應用程式讓你連結到Google網站(大多走OAuth模式),讓你同意授予某些權限,App的這個動作就是在取得你授予的Token,取得後,應用程式會把該Token保留起來,以便於後續使用。

你可能會擔心,那該應用程式或第三方網站不就可以存取你的某些資源(例如Google Docs, Calendar…etc.)? 是的,正是如此,因此Token多半有時效性,可能是數天,也可能是一兩年,依照授權決定。那萬一Token外洩,撿到的人不就有可能用該App或第三方網站的身分來存取你的資源? 也沒錯,所以Token多半不會公開顯示,傳輸過程也必須透過加密(SSL),甚至儲存位置也要謹慎(最好別儲存)。

Token安不安全?

安不安全,就看你(第三方網站或App)怎麼使用!

Token的本質跟secret差不多,基本上都算是機密資料,不該公開,不能外洩,不應隨意儲存。最安全的使用方式是取得Token立即拿來用,用完就丟(刪除),不要儲存在任何地方,只停留在記憶體內,這樣當然最安全。

但如果有一個應用程式(或網站),一天到晚需要你重新登入Google帳密只為了取得新的Token,你一定會覺得很煩,所以大多應用程式取得Token之後,都會自行保存起來,能用多久就用多久(這意味著,只要Token沒失效,該應用程式就可以存取你的資源。你發了這Token,其實就意味著你信任該應用程式)。而該應用程式把Token存在哪裡,就成了關鍵。

理想的存放位置是後端DB或是更安全的環境,手機App取得Token之後,如果存放在App的storage是否安全? 網站取得Token後,如果放在 local storage是否安全? 這都是相對的,只要儲存了,就『相對』不安全。但如果不儲存(或是效期太短),需要使用時就得常常重新取得Token,一天到晚讓用戶重複輸入帳密,不僅麻煩,也不見得安全。

所以儲存是迫不得已的事,而儲存安不安全,跟前面的Cookies相同,只要OS和App本身不被駭,不會有其他程式碼有機會讀取到該App的資料,那基本上是安全的。

Token的用途

所以,Token主要的(原始的)用途就在授予某種權限,應用程式可以保存Token,無須知道用戶帳密,就可以拿著Token存取用戶授予的資源。這也是Google Docs、Calendar這類的資源常常可以安全的讓第三方應用程式或網站存取的原因。

除此之外,Token也可以被用來作為具有某種身分的象徵。例如前後端分離的SPA網站,當用戶驗證完帳號密碼之後,後端可以自己發一個Token給前端,前端取得該Token之後,就可以在未來呼叫後端的API時,把Token當作參數在http header中,傳遞給伺服器端,伺服器端的WebAPI可以檢視該Token是否有效是否到期,來決定是否允許前端呼叫。

而這種身分驗證方式採用的Token格式,近年來最常見的做法就是 JWT(JSON Web Token)。JWT是一種open source的Token格式,任何開發人員都可以自行依照該格式建立出一個Token,其格式包含三個部分,分別是:

  1. Header
  2. Payload
  3. Signature

我們暫且不討論它的技術細節,你可以在底下這個連結看到更多詳細的內容: https://en.wikipedia.org/wiki/JSON_Web_Token

如果你有興趣,可以用底下這個網站自己建立一個 JWT:
http://jwtbuilder.jamiekurtz.com/

然後用底下這個網站來解析(Decoded) JWT:
https://jwt.io/

你會發現,JTW中的Payload,可以包含登入者的身分資訊(或其他必要資料,因為不需要secret即可decoded,所以很方便作為用戶身分的保存與取得),且因為Signature有透過secret做Hash,則可用來讓token的發行者作為檢核之用,確保該token是自己發行的,不曾被竄改。

對於asp.net應用程式而言,一般來說,JWT有底下幾種典型用途:

  1. 前後端分離的SPA(Single Page Application)應用程式的身分保存(也就是無狀態下的身分維持機制)
  2. WebAPI呼叫時的身分驗證

上面這兩種作法的行為,其實都很類似前面一開始介紹的模式,用戶從前端輸入帳密,呼叫後端API驗證完身分之後,後端自行建立一個JWT(Token)發給前端。未來,前端(Browser上的JavaScript)有任何對後端(WebAPI)的呼叫,都使用這個Token作為身分識別(作法是夾帶在http header中)。

後端WebAPI取得這個Token之後,可以驗證該Token是否為自己所發(透過Signature),也可以得知用戶的身分(透過Payload)。如此一來,簡單的解決了SPA和WebAPI呼叫的身分驗證(身分抓取)問題。

這和Cookies驗證有何不同?

講到這邊,我真的覺得我寫太多了,一寫起來,文章像是自己有生命一樣停不來。不過,有了前面的基礎,我們開始可以討論一些問題了…

不知道你會不會聯想到一個問題,這樣JWT Token若在SPA網站上使用,跟前面的Cookies驗證有何不同?

你會發現。其實本質上是差不多的。身分驗證完畢之後,給前端發個記號(令牌),接著在前後端交互(WebAPI呼叫、或是頁面巡覽)的過程中,在http header中夾帶著這個記號(令牌),讓伺服器端可以驗證,並且達到識別且維持身分的效果。差別只在 Cookies驗證中採用的是Cookies,而JWT則是自己發的Token。

所以,傳統的非SPA網站,例如 asp.net MVC(含WebForm)或是 .net core的MVC或Razor Page,是否需要以JWT做身分識別? 從我的角度來說,我自己覺得其實不需要,採用內建的 Cookie Authentication就可以了(輕鬆方便)。若採用JWT反而麻煩,不僅發token和解析token與維持身分的code都要自己撰寫,頁面切換(submit)的過程中,要保存token不落地(不儲存)也頗煩人,最後還是得把JWT(Token)存在localstorage或cookies中,結果跟使用cookie authentication本質上沒啥兩樣。

SPA的身分驗證機制

但SPA(Single-Page Application)呢? SPA則毫無疑義,使用JWT方便得多,而且由於SPA大多徹底的實踐了前後端分離,因此換頁(submit)的機會少,大多前後端交互都採用AJAX呼叫,所以透過JWT保存(維持)身分、呼叫後端API都很方便。因為前端不太需要換頁,所以JWT可以安全的保存在記憶體中就好,無須寫入Local Storage,瀏覽器關掉就失效,下次開啟瀏覽器重新登入即可,這樣才能有高安全性,否則隨意儲存JWT(Token)其實風險可能更高。

WebAPI的身分驗證

那WebAPI的身分驗證呢?

我自己覺得使用Cookies驗證或JWT(Token)的形式其實都可以,因為兩種都能輕易達成。如果我的網站本質上是MVC或RazorPage,那我會選用 Cookies驗證。但如果我的網站是SPA,那我會選擇JWT,總之跟著網站(網頁)的行為就好,簡單方便又具有一致性,無需特別做另一套。但如果你沒有具有網頁的網站,只是單純做WebAPI(給前端或其他應用程式呼叫),則隨意,用哪一種都可以。但如果用戶端只有手機,或是用戶端有可能跨網域,那我會選擇JWT,因為手機或Web/Desktop應用程式要模擬Cookies的保存必須實作一個 Cookies Container,相對麻煩一些。

總結

到這邊,你大概知道了 ASP.NET Web應用程式(不管是 .net core或是 .net framework,不管是MVC或Razor Page或SPA)進行身分保存(維持)與實現登入功能的原理。我們後面接著要來討論,在這個原理底下,Web應用程式的SSO(Single-Sign On)是如何實現的?

未完,待續

參考課程:https://www.studyhost.tw/NewCourses/aspnetcoreauth

.net core 採用 Cookie驗證下的用戶身分抓取

enter image description here

關於 .net core的登入與身分驗證方式

前情提要…

前幾天,我們示範了如何在 .net core 環境下,使用 cookie-based authentication 來實現登入與身分驗證功能。這個做法是從 .net framework以來就有的,也是延續到 .net core 最簡單且輕量級的身分驗證(登入)方式。

整個作法的影片在底下:

https://youtu.be/ag9vQX9GAPs

當然,ASP.NET Core和 ASP.NET Framework 一樣,另外還有一整套 ASP.NET Core Identity機制,這套機制非常完整,除了基本的身分驗證,還包含權限管理、角色(Role)、Token、電子郵件驗證、忘記密碼…etc. 功能繁多。但當然也笨重很多。對於資料庫和身分管理邏輯也有一定程度的相依性。

也因此,我自己比較喜歡 cookie-based authentication 的簡單方法。

而採用了 cookie-based authentication 後的網站,可以透過 C# 後端程式碼,以很簡單的方式透過底下這樣的指令:

User.Identity.Name

就可以抓取到當前登入的用戶名稱。詳細的做法,在上面的影片中我們已經初步的介紹了。

接著,有讀者問到了OAuth的驗證整合,最常見的就是Google 登入。Google登入是什麼呢? 你會看到最近很多網站,都採用Google帳密登入,而非使用網站自己的帳密(也或許是兩者同時)。

所謂的Google 登入驗證,是一種SSO(Single-Sign On)登入機制,採用的其實是一套業界標準的OAuth機制,除了Google以外,Microsoft、Twitter、LINE都有利用這個標準做出了自己的登入功能。相關的說明您可以參考筆者之前的介紹。採用這個機制時,網站不需要知道用戶的Google帳密,只需要把身分驗證這一段,丟給Google去作,作完後把結果以Token回傳給網站。

透過Google SSO登入之後,我們可以取得用戶的Token,藉由Token取得用戶的身分(email),接著,再利用前面介紹過的cookie-based authentication,把取得的 email 視為用戶已登入的帳號,以該帳號完成用戶登入,如此一來,就在 .net core的 WebApp(Razor Page)實現了 Google SSO 搭配cookie-based authentication的身分驗證功能,這部分可以參考底下這個Lab,你會看到整個開發流程,以及實作出來的結果:
https://github.com/isdaviddong/HOL-DotNetCore/blob/master/Auth/使用 .net core 搭配 Google SSO(Single-Sing-On).md

讀者請留意,你必須先申請Google SSO所需相關資訊,像是Client_id, Client_Secret,才能夠實作上面這個Lab

WebAPI怎麼辦呢?

但接著,又有另一位讀者問到另一個問題,那如果我要搭配WebAPI,該如何作呢?

嚴格來說,WebAPI中要抓取用戶身分,其實跟Google SSO/OAuth無關,純粹就是cookie-based authentication得延伸,只是剛好我們先使用了Google SSO作為用戶的身分而已。

因此,我又作了Github上的這個範例:
https://github.com/isdaviddong/dotnetCoreWebAppGoogleSSOWithWebAPI/
這是一個razor page + Web API的範例,登入採用Google SSO,完成後以cookie-base的方式保存身分的範例。

但請看其中的WebAPI:
https://github.com/isdaviddong/dotnetCoreWebAppGoogleSSOWithWebAPI/blob/main/ValuesController.cs

你會發現,一但身分保存之後,在WebAPI中一樣直接透過

User.Identity.Name

就可以抓取到用戶身分,一個簡單的WebAPI程式碼如下(11行):

就這樣,不管你在 Razor Page, MVC, WebAPI都可以輕鬆的抓取當前呼叫的用戶身分。

使用 cookie-based authentication 這個架構很簡單漂亮,這讓後端C#中的程式碼(不管是MVC, Razor Page, WebAPI),都很容易的可以得知當前的用戶是誰。

如果你作的是一個企業內的商業應用程式,或是一個B2C或B2B的網站,那透過這樣的模式,在前端呼叫後端API時,不需要額外採用Token方式去驗證用戶身分,可以大幅降低開發時間,同時確保API被呼叫的安全性(可以輕鬆在API中檢查用戶身分)。

如果你採用前後端分離的架構,前端的開發框架(例如Vue),想要呼叫後端的WebAPI時,也可以透過這樣的方式,後端的C# Code自然而然能夠得知用戶身分,只有一個前提,前端必須在同一個domain。

那如果,前端是手機或另一個domain,要支援跨domain的身分驗證呢?

那就是另一個故事了…改天,再找機會繼續跟大家說明。

參考文件

A> Use cookie authentication without ASP.NET Core Identity

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-5.0

B> Introduction to Identity on ASP.NET Core

https://docs.microsoft.com/zh-tw/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&tabs=visual-studio

相關課程:

https://www.studyhost.tw/NewCourses/aspnetcoreauth
https://www.studyhost.tw/NewCourses/Architecture

2021年1月15日 星期五

透過容器化使用LUIS在地端進行語意分析

透過容器化使用LUIS在地端進行語意分析

enter image description here

應該大家都知道,微軟從幾年前開始,推出了一系列的AI服務,稱為Cognitive Services,內容包含可以識別人臉、辨識圖片內容的電腦視覺,可以即時聽寫(語音轉文字)或輸出(文字轉語音)的Speech API,可以透過類神經網路翻譯的Translator API,還有可以讓chat bot認得用戶輸入的文字的LUIS與QnA…等。

這些服務在雲端上固然方便好用,但每次上課都會有學員問到,可不可以把模型匯出然後在on-premise環境做辨識?

一般會有這種需求不外乎兩個理由,其一是速度,另一個更重要的則是安全性,因為客戶往往不希望要辨識的圖像或文字透過網際網路被傳遞到遠端的伺服器中。

可以嗎? 是的。現在,透過容器化技術,你可以這麼做了。
如今大部分的cognitive services都開始支援容器化的應用方式。我們可以從雲端下載LUIS run-time的image,然後把在雲端上訓練好的模型下載後,透過Container技術在客戶端(用戶端)在on-premise環境做辨識。

怎麼做呢? 其實很簡單。

首先,透過docker command下載雲端上的LUIS run-time(如果在windows上使用,必須安裝好docker desktop):
enter link description here

完成後,從https://www.luis.ai/網站上把訓練好的luis模型也下載下來:
enter link description here

你應該會下載到一個.gz檔案。
接著建立兩個資料夾,分別是 C:\input 與 C:\output ,用別的路徑當然也可以,後面的docker run指令配合著修改即可。

把剛才下在好的.gz檔案放入 input 資料價,請注意如果需要時要調整檔名,檔名格式為 LUISAppID_PRODUCTION.gz :
enter link description here

上述都準備完成後,請執行剛才下載的 docker image:
enter image description here

上面docker run指令的格式為:

docker run --rm -it -p 127.0.0.1:5000:5000 --memory 4g --cpus 2 `  
--mount type=bind,src=c:\input,target=/input `  
--mount type=bind,src=c:\output,target=/output `  
mcr.microsoft.com/azure-cognitive-services/luis:latest `  
Eula=accept `  
Billing=https://XXXXXXXXX.cognitiveservices.azure.com `  
ApiKey=78XXXXXXXXXXXXXXX21

其中的billing可設為你的Luis服務的endpoint,ApiKey當然是你的LUIS服務的Key。

你會發現,透過這樣的執行後,LUIS Container被執行了起來,我們可以在Localhost:5000看到LUIS服務了:
enter image description here

而辨識的API,也可以從localhost呼叫到了:
enter image description here

很讚吧。
感謝Docker感謝Container,讓一切變得如此簡單。

ref:
https://docs.microsoft.com/zh-tw/azure/cognitive-services/luis/luis-container-howto?tabs=v3

熱門文章