台灣最大程式設計社群網站
線上人數
1250
 
會員總數:244873
討論主題:188880
歡迎您免費加入會員
討論區列表 >> PHP >> 驗證方法的安全性
[]  
[我要回覆]
1
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
驗證方法的安全性
價值 : 80 QP  點閱數:680 回應數:10

樓主

淺水員
中級專家
2537 4
1657 294
發送站內信

我想詢問如果我用下列方法驗證「資料上傳」是否由合法使用者執行的。這樣的架構是否安全?

一、伺服器保存資料(假設伺服器沒被破解,且上傳時沒被竊聽):
$pwd=hash過的密碼

二、客戶端POST參數:

$_POST['time']=發出http請求的timestamp
$_POST['data']=想上傳的資料
$_POST['hash']=hash(想上傳的資料+timestamp+hash(pwd))
※這邊的hash由javascript計算,pwd由inputbox輸入

三、伺服器端:

檢查$_POST['time']與time()相差不超過15秒
檢查hash($_POST['data']+$_POST['time']+$pwd)是否等於$_POST['hash']

以上建立在單一使用者的狀況,不知道這樣安不安全,是否有什麼方法會被攻擊?

搜尋相關Tags的文章: [ 雜湊 ] , [ 時間戳 ] , [ 密碼 ] , [ 安全 ] , [ hash ] , [ timestamp ] , [ password ] ,
本篇文章發表於2016-09-29 14:10
別忘捐VP感謝幫助你的人 新手會員瞧一瞧
1樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
一般來講,想要防合法性。
其當key值的資料都要由後端來提供才會比較安全。

用時間性雖然會比較好。可惜時間性的部份比較沒辦法用md5的方式處理。
所以一般我這媟|用base64的方式來帶出。再加上一些特殊碼來轉換。

只是這樣子做也是有其缺點。不能放太多資料。要不然其編碼就會很長非常的不適合。

所以我比較常用的是另外一種方式。時間採用base64編碼。再加上一個隨機產生的key碼。雙碼判斷驗証處理。

再安全性上可以用確保資料來源是你的來源位置。可以用上一頁的網址來判斷是否由你的主機發出。
key碼可以連帶儲存到session上做判斷處理
給你我用的特殊編碼。這原本我是拿來做驗証圖處理用的。我將其編碼的方式給你研究

本篇文章回覆於2016-09-29 16:08
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
2樓
作者回應

淺水員
檢舉此回應
請問我是否可以理解是否正確?
客戶端必須傳送的資料為:validcode函數的兩個參數$hcode、$code
而這兩個參數的意義為:
$code=原始資訊
$hcode=加密函數(原始資訊,時間戳,HTTP_USER_AGENT,secret_string)

所以在網路上傳輸的資料有:$hcode、$code、HTTP_USER_AGENT

僅儲存在客戶端或是伺服器的變數為:時間戳、secret_string
(其中「時間戳」是加密後在網路上傳輸,secret_string則由使用者輸入)

也就是說$hcode、$code、HTTP_USER_AGENT是可以透過竊聽取得的?
此外客戶端也存在加密函數的方法

這樣一來,防護的狀況似乎跟我原本提的差不多,HTTP_USER_AGENT經由竊聽後要偽造似乎不是難事?
此外竊聽者可以把$code跟$hcode做XOR運算,得到validateCode的$key值?

PS.我也想分享我的程式碼,但因為在開發中還沒整理好,所以只先丟github
取得雜湊的部分,我是自己實作SHAKE-128(SHA3的一部分),是直接對陣列做雜湊。所以單純轉碼的問題我是知道怎麼處理的。

(以下稍微離題)
專案中SHA3.php,是可以直接拿來用的。使用時直接呼叫SHAKE128即可:

本篇文章回覆於2016-09-29 22:21
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
3樓
回應

Ricky是我
檢舉此回應
關於 "合法使用者" 的認定基本上就有點問題
因為 HTTP 協定的先天架構 請求 -> 回應 -> 斷線
所以你根本無法確保,這次連線跟下一次連線的 "人" 是否同一個
甚至有可能你的 Server 架構是採用 Load Balance,每次請求回應的 Server 甚至是不同一台。

因此保留狀態 (Keep State),就成了 Web 應用程式的基本功能。
在 PHP 上的實作就是 session。

Session 的實作上分成兩部分
1. session id
2. session store

session id 指的是不管你是誰,只要你有辦法提供 session id,我就認定這個身份,通常是是透過 cookie 來實現。
有了 session id 就可以用查表的方式,找出剛剛你存下來的資訊,再呼叫出來還原。這就是透過 session store 來實現。也就是 php 中的 $_SESSION

其實只要使用 PHP session 機制,基本上不需要使用這堆奇奇怪怪的方式去 "重造輪子"。
但或許你會質疑如果 session id 被竊取,那不就沒用。
所以為了避免這個狀況,通常會搭配 SSL ,避免中途被擷取或是連上釣魚網站。

另外一個議題是 "違反使用者意願" 去做出錯誤的請求 (CSRF 攻擊)
舉個例子
假如你今天登入了某個網站,所以系統會起始一個 session ,並且把 session id 存入 cookie 中。
這個網站是透過某個 url 做刪除文章的動作例如 http://example.com/post/123/delete 當點選這個 url 時,就會刪除 id = 123 的文章。
攻擊者當然知道你的文章 id
所以他只要在論壇上面貼上 <img src="http://example.com/post/123/delete"> ,請你來看一下這篇文章。
這時瀏覽器就會發出 GET http://example.com/post/123/delete 的請求,因為你是登入狀態 (有 session id),所以文章就被刪除了。
問題是對你來說,你的行為是要 "看文章",但是瀏覽器並不懂,這個網址的行為究竟是 "取得照片",還是 "刪除文章"。
要避免這個方式的攻擊,實作上會加上一個特別計算出來的 hash 當作參數,這個參數每個人都不一樣,只有自己才知道。
像這樣 http://example.com/post/123/delete?csrf=abcdxxxx ,攻擊者並不知道你的 hash,所以上面的攻擊法就會失效。

其實這個攻擊法最大的問題在於,你無法透過 JS 去控制每個請求是否送出 cookie,偏偏整個 session 又是依賴在 cookie,就會發生這個狀況。
所以現在有許多基於 REST API 實作的網站,都不用 cookie 來實現 keep state,而是使用 JWT token,一方面避免 cross domain 的問題,另一方面,也可以選擇哪些時候要送出身份識別( token / session id )。

希望這些訊息能對樓主有所幫助
本篇文章回覆於2016-09-30 09:58
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
4樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
這堨說明一下運做原理好了。

其實我上面的程式是拿來做驗証碼圖用的。
我的驗証碼圖不做儲存session處理。
而是用直接帶入代碼的方式驗証處理的。

1.首先~~~先產生一個key跟代碼。這堛漸N碼用code做說明。

2.代入code後產生出來validateCode的編碼代碼hcode。

3.只對html輸出key跟hcode。

4.在發送的同時,用javascript利用該key去產生code後。代入數值傳送給後端。

5.後端接收到原hcode再加上新產生的code。驗証處理


以上的情況,認真來說需求會有3個值

key值 = 用來產生code的依據,但不當檢查值。html可視。
code值 = 由key值產生出來的特殊值,不做傳送依據。也不會事先產生在html上。
hcode = code編碼後的代碼。為主傳送依據。也是拿來當檢查碼用的。

也就是說,雖然在html上,最多只能看到key跟hcode值。

而這堨i能要先解決一個問題。那就是javascript程式碼可視的問題。
所以再用key值轉換code的過程。會被發現而找到其編碼過程。
我這堿O採用ajax處理編碼轉換
本篇文章回覆於2016-09-30 09:59
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
5樓
回應

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
一般來說,如何判斷本機安全性原則。
都需要保持如下的方式

1.代碼不可逆原則:
一般大多數是採用md5方式。只是如果要搭配時間判斷的話。
不可逆的原則就很容易強碰無法處理。
所以會用雙代碼的原因就是在此,一種可逆另一種不可逆處理。
讓用戶無法了解這些代碼轉換。

2.代碼不可讀取帶入即可使用:
原則上,代碼一般是需要給瀏覽器使用。相對的,用戶自然可以讀取該代碼。
所以要確保每一次產生的代碼,是不可再次利用的。
但這就需要智慧了。用過期的方式雖然也是一招。
但時間上也不能太短。
我比較常用的方式是代碼儲存在session上。並記錄次數
當使用過就將其消失處理。這樣就算用戶想要特殊請求的方式。
只要未經過產生頁面的處理。自然該代碼就無法使用第二次以上。確保其唯一性。
本篇文章回覆於2016-09-30 11:51
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
6樓
作者回應

淺水員
檢舉此回應
先謝謝兩位的回應。
因為內容比較多,我沒法在短時間內一次回應,先說聲抱歉。

我想先說明一下我網站的目標:

我在做一個提供使用者下載資料的平台,像是「下載區」那樣。
所謂合法的使用者是我用詞不當,應該改正為後臺操作的驗證。
因此可以簡化為以下兩類:
(1)任何人:可讀取(下載),但無法任意刪除或上傳。
(2)後臺操作人員:具有讀取(下載)、上傳、刪除的權限。

安全上的要求是
(1)輸入正確密碼即可進行後臺操作。
(2)網路可能被竊聽的狀況下,無法透過竊聽得到可以任意上傳、刪除檔案的權限。

我稍微整理了一下我用的方法,用下圖來表示。這樣應該比文字更清楚:
(用刪除檔案的驗證當作例子)



竊聽者最多只能重送相同的訊息,但資料既然刪除了,收到相同的訊息也不會進行操作。
竊聽者在不知道密碼或是Key的狀況下,也無法竄改檔案的id,即使javascript是透明的。
單靠竊聽要破解出Key,就是相當於破解一個加了salt的hash。

To Ricky是我:
我認為透過輸入密碼的機制,是可以防止「CSRF 攻擊」的。

To 浩瀚星空:
您的驗證機制我還在研究,可能要晚點才回應。
本篇文章回覆於2016-09-30 17:24
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
7樓
作者回應

淺水員
檢舉此回應
To 浩瀚星空:

因為對這問題感興趣,所以即使我們做的驗證目的不同,我也想弄清楚您的想法。

下圖是根據您給的程式碼所畫的加密流程:

我想必須先確認的是:
1. 您在4樓所說的key跟code分別對應到上圖的哪兩個變數呢?
2. 您在4樓有提到「首先~~~先產生一個key跟代碼。這堛漸N碼用code做說明。」這邊的key跟code是分別獨立產生的,還是只產生一個,另一個由計算得出?
3. secret是否為寫死在PHP中的呢?還是其實圖中的secret是您在4樓所說的key?
4. 您這個程式驗證的目的是什麼呢?
本篇文章回覆於2016-10-01 23:27
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
8樓
最有價值解答

Ricky是我
檢舉此回應
首先我針對樓主提出幾個澄清

1. CSRF 攻擊並不是針對帳號密碼攻擊,他主要的弱點在於 "無法得知意圖" 的請求。即使加上了帳號密碼驗證 (只要你是依賴在 SESSION/COOKIE),就會有這個弱點。
2.與其自己搞這堆 hash 演算法,不如直接使用 SSL 不是比較省事。SSL基本上已經經過大量的檢驗過了,安全性上沒有太大的問題。
而且全程加密,也不用擔心資料外洩的問題,現在要取得 SSL 憑證也相當容易, Let's Encrypt 也有提供免費的 SSL 憑證。
如果搭配 HTTP2(強制走 SSL) 效能比原本 HTTP1 未加密連線還快,為什麼要如此堅持自己算 Hash 勒。
而且在 SEO 上,走 SSL 還可以享有比較優先的排名。

再來就是針對 Hash 演算法, MD5 目前已經被標示為棄用了,要算出 Hash 碰撞已經不是什麼難事,在幾十分鐘的時間內就可以算出碰撞。

針對樓主需求,比較好的作法應該是
Cookie/SESSION +SSL (正確說法應該是 TLS SSLV2/3已經被棄用),將身份識別存於 SESSION 中,去區分一般 User 或是後台操作人員。
如果你想走的是 Session Less (Server端不保存任何有關 Session 的資料),實作 JWT Token(這個也是業界標準,有一堆套件支援),將身份識別資訊存於 Token 中,藉由 Cookie 帶回 Server 端。
本篇文章回覆於2016-10-03 09:51
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
9樓
不錯的參考

浩瀚星空
捐贈 VP 給 浩瀚星空 檢舉此回應
你好:

其實這是我之前做的驗証圖代碼處理的。

validateCode的作用只是單純加密解密用的一項特殊計算。
混合著md5跟base64的處理。

我想在這塈A不會了解的原因,是因為我並沒給你code產生的相關。

實際上,我的code產生是放在其它的程式組上產生的。
其產生的資料會是如下 「隨機碼@運行時間(這堿O使用unixtime)」

所以我上面的程式中驗証 validcode 的處理。會有一個list($string,$mytime) = explode('@',$decode);

就是將解密後的資料取回再加以判斷處理。

當初這樣設計的用意,是因為並不太想利用session或是cookie來做記錄處理。
所以會將所有的資料都做加密來處理的。

而在html上。如我這是驗証圖。它的所有的東西,都是利用加密代碼來自動產生的。
也就是說在html上,也只能看到加密代碼。看不到其它代碼。

而加密代碼的產生全利用ajax或是主控連結的方式。
如我的是驗証圖。

則會用如<img src="val_img.php?code=<?php echo $hcode;?>" />

這樣的方式來處理產生對應的驗証圖了。

所以說穿了。這其實只是一種加解密代碼的方式。

真正要運用的是,你要如何去產生原始代碼處理。

而這塈琤i以幫你想到的就是。唯一key的原理。也就是其key值可以利用session或是db庫來去應用產生。
但該代碼被使用過就消失處理。

這我曾經運用過。這樣的方式會比較單純。也比較無需加解密處理。
也就是當頁面產生的同時,就連帶產生一組對應代碼。這代碼可以明碼送給html內。
反正讓他們知道也沒關係。因為也只能用一次而已啊。

當該代碼被使用後就消失了。
本篇文章回覆於2016-10-03 10:02
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
10樓
作者回應

淺水員
檢舉此回應
To Ricky是我:

SSL我雖然還不會用,但也是知道的。我完全明白很多安全問題,SSL可以解決。
不過此刻,可以當作這個討論串是學生在討論功課,做研究。
也就是說可以當作是我個人的好奇心吧!
(我本身沒在資訊業工作,純興趣)

您提到「依賴在 SESSION/COOKIE」這點,我在6樓的圖中。並沒有使用cookie。
密碼只是要求使用者輸入在<input type='passwoed'>中。
然後旁邊有個<button>,點選後才與sever連接要求刪除檔案。

這邊並沒有保存「帳號」、「密碼」或是「登入的相關資訊」,唯一有的只有用SESSION保存一個unix timestamp。(以刪除檔案的例子是可以拿掉SESSION的)
也可以說我並沒有實作「登錄」這個功能。
每次傳送訊息,都會重新計算傳送資料該有的雜湊值,這應該算是數位簽章(Digital Signature)的一種。

至於md5的問題,那只是因為浩瀚星空給我的程式碼就是md5。
討論時以原資料討論比較好溝通。
(想換的話函數抽換掉就可以了,所以並沒著墨在上面)

不過我很感謝您提供的資訊,因為我還不知道有免費的 SSL 憑證,也不知道HTTP2、HTTP1這些事情。
也透過您的訊息,我才知道CSRF這個名詞還有cookie的特性。

To 浩瀚星空:

您提到「只能用一次」這個概念,有提醒到我可以增加的部分,感謝。
(有點像是「challenge/response」的模式了)
本篇文章回覆於2016-10-03 17:01
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
   
1

回覆
如要回應,請先登入.