2009-09-11 63 views
3

哪一部分(S)比方說,我有這樣的SQL語句來檢查用戶登錄:確定的WHERE語句失敗

SELECT * FROM users 
WHERE username='[email protected]', password='abc123', expire_date>=NOW(); 

是否有SQL的方式來確定具體哪些WHERE條件達不到,不必須將每個條件分解爲自己的查詢並單獨測試?

在這個特定的例子中,開發人員可以準確地告訴用戶他們嘗試登錄失敗的原因。

爲了我的目的,我使用的是PHP/MySQL。

+1

expire_date的時間部分可能小於NOW()中返回的值,導致查詢不返回您期望的結果。 – 2009-09-11 17:17:20

+0

謝謝,我意識到,即使名稱有些誤導,該字段也會存儲時間。 – macinjosh 2009-09-11 17:19:37

+3

你打算把失敗的原因傳給用戶嗎?這可能會讓黑客更容易獲得訪問權限。 – 2009-09-11 17:25:54

回答

0

這裏是我想出了:

SELECT 
    IF(mem_username='[email protected]','true','Error: Bad Username') AS mem_username, 
    IF(mem_password ='abc123','true','Error: Bad Password') AS mem_password' 
FROM MEMBERS 
WHERE mem_username='[email protected]' AND mem_password='abc123' 

這樣我可以在代碼中發現了錯誤信息,然後顯示它們是必要的。

注意:對於大家引用示例代碼的安全問題,感謝您的關注。但是,這不是真正的生產代碼,這僅僅是一個簡單的例子來證明我的問題。很明顯,您不應該以明文形式存儲密碼,也不應該爲用戶提供關於登錄失敗原因的具體信息。

+0

不要幫助黑客讓他們知道他們已經得到用戶名和密碼錯誤!另請參閱其他人關於不在數據庫中明確存儲密碼的回覆! – 2009-09-11 17:52:49

+0

這個SQL真的很拗口;首先,重複一個字段名稱作爲別名是不好的計劃; 秒,它永遠不會給你一個錯誤信息 - WHERE子句將只返回使兩個IF子句都爲真的記錄; 第三,'糟糕的用戶名​​'測試有點離奇;你真的想告訴某人'你有正確的密碼,但對於不同的用戶'? 我建議 SELECT IF(mem_password_hash = 'c0e1732fa',真,假) 議員WHERE mem_username='[email protected]」 你已經知道用戶名;如果它返回true,則它們通過,false表示錯誤的密碼,NULL表示錯誤的用戶名。 – 2009-09-11 23:26:34

6

那麼,你可以做的一件事就是改變你的查詢,所以它只匹配用戶名。然後在代碼中檢查密碼和到期日期,返回適當的錯誤。

另外,我希望你的例子查詢是一個簡化;當然,你應該醃製/加密/散列你的密碼,並且你應該包括一些限制在一定時間內失敗的嘗試次數等等......

就你的實際問題而言正在尋找),沒有辦法從where子句中獲取該信息。你可以做最接近的將是這樣的:

SELECT *, 
    CASE WHEN Password = 'asdf' THEN 1 ELSE 0 END AS IsPasswordMatch, 
    CASE WHEN Expiration >= NOW() THEN 1 ELSE 0 END AS IsActiveAccount 
FROM Users 
WHERE Username = 'user' 
+0

由於我們目前的代碼結構,只有SQL的解決方案是理想的。 – macinjosh 2009-09-11 17:22:37

+1

這是推薦的方法。根據名稱獲取用戶行(如果失敗,沒有用戶),然後比較密碼散列(如果失敗,則輸入錯誤密碼),最後存儲行ID(用戶ID)以及會話中的其他內容並將其登錄。 – Xeoncross 2009-09-11 17:25:52

1

不行,where子句被應用爲塊,以及各種技術被用來使得不是所有行先要進行掃描。另外,你怎麼知道哪一行是所需的?

另外,您可能不想告訴用戶太多關於登錄嘗試失敗的原因。說太多就會導致諸如帳號挖掘和密碼攻擊等攻擊。

編輯如果你真的不想要顯示給你的用戶,然後分裂你的邏輯分成不同的部分:

  1. 驗證身份
    操作:從數據庫 獲取相應的用戶行
    結果:
    • 如果沒有這樣的行存在=>無效帳戶
    • 如果返回行,繼續步驟2
  2. 驗證憑證
    操作:檢查所存儲的憑證(密碼,密碼的散列或加密的密碼)對以相同的方式處理提供的密碼憑證被存儲。
    結果:
    • 沒有匹配=>無效的密碼/憑據
    • 匹配=>成功登錄嘗試
  3. 登錄用戶
    操作:將數據添加到會話等。
+0

在我的具體情況中,我們確實想告訴用戶這些信息。我們已考慮到安全風險。 – macinjosh 2009-09-11 17:22:02

+0

這(和法案)仍然是最好的答案。僅僅因爲你的查詢返回結果並不意味着你實際上已經把所有的信息都提供給了用戶。 – longneck 2009-09-11 17:34:59

+0

對,我同意。一個人不必公開auth失敗的原因。但開發人員可能仍然想知道給定用戶帳戶的重複失敗密碼,例如建立鎖定。 – 2009-09-11 17:40:51

0

你可能只需要對部分分開與where子句「與」

SELECT * FROM users 
WHERE username='[email protected]' 
    And password='abc123' 
    And expire_date>=NOW(); 
4

在MySQL中,你可以把布爾表達式在選擇列表中。布爾表達式的計算結果爲true時爲整數1,否則爲false。

SELECT password = 'abc123' AS is_authenticated, 
     expire_date >= NOW() AS is_not_expired 
FROM users 
WHERE username='[email protected]'; 

注:如果你需要寫上其他品牌的RDBMS的工作的查詢,請記住這個使用布爾表達式的是非標準的。使用其他人發佈的CASE語法。

PS:這是您的問題的切線,但我強烈建議您不要以明文形式存儲密碼。存儲醃製密碼的散列摘要。見How does password salt help against a rainbow table attack?

+0

感謝您對我的安全性的關注,這真的只是一個查詢不是真實的事情!我同意哈希是必須的! – macinjosh 2009-09-11 17:35:23

+0

好的,酷,我想也許你的查詢是從真實的東西簡化了,但我想確保提及哈希以防萬一。 :) – 2009-09-11 17:38:57