簡體   English   中英

OpenEdge中的WS-Security,續

[英]WS-Security in OpenEdge, continued

作為此問題的后續: 實現WS-Security in Progress ABL ,我將繼續努力實現WS-Security in Progress OpenEdge。

我的問題:

在對特定Web服務的每次請求中,我都會基於以下內容生成密碼摘要:

  • “ nonce”-隨機字符串
  • 時間戳記-當前時間
  • 密碼-我和Web服務提供商之間的共享機密。

然后將現時,時間戳記和摘要添加到Web服務調用的Soap標頭中。

這在大多數情況下都可以正常工作,但在100個請求中有5個失敗(請參見下面的更多信息)。

這是我生成摘要的方式:

PROCEDURE generatePassHashNonceClear:

/*------------------------------------------------------------------------------
  Purpose: 
    Generates a password hash for WS-Security

  General algorithm:
    Digest = base64(sha1(Nonce +  Timestamp + sha1(Pwd))) 
------------------------------------------------------------------------------*/
    DEFINE INPUT  PARAMETER pcNonce    AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcCreated  AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcPassword AS CHARACTER   NO-UNDO.

    DEFINE OUTPUT PARAMETER pcHash     AS CHARACTER   NO-UNDO.

    DEFINE VARIABLE mBytes        AS MEMPTR      NO-UNDO.
    DEFINE VARIABLE mSHA1         AS MEMPTR      NO-UNDO.

   /* 
    Set size of mempointer, add 20 since we are adding the 20 byte 
    SHA1-DIGEST of the clear password in the end.
    */
    SET-SIZE(mBytes) = LENGTH(pcNonce) + LENGTH(pcCreated) + 20.

    /* Put the decoded nonce first */
    PUT-STRING(mBytes, 1) = pcNonce.

    /* Add create time */
    PUT-STRING(mBytes, 1 + LENGTH(pcNonce)) = pcCreated.

    /* Set SHA1 returns a 20 byte raw string. */
    SET-SIZE(mSHA1) = 20.
    mSHA1 = SHA1-DIGEST(pcPassword).

    /* Add password, SHA1-digested (so we need to put bytes instead of a string */
    PUT-BYTES(mBytes, 1 + LENGTH(pcNonce) + LENGTH(pcCreated)) = mSHA1.

    /* Create out-data in B64-encoded format */
    pcHash = STRING(BASE64-ENCODE(SHA1-DIGEST(mBytes))).

    /* Clean up mempointers */
    SET-SIZE(mBytes) = 0.
    SET-SIZE(mSHA1)  = 0.

END PROCEDURE.

這是該過程的調用方式:

DEFINE VARIABLE cPasswordClear   AS CHARACTER   NO-UNDO.
DEFINE VARIABLE dtZuluNow        AS DATETIME    NO-UNDO.
DEFINE VARIABLE cCreated         AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cNonceB64        AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cNonce           AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cPasswordDigest  AS CHARACTER   NO-UNDO.

/* 
Get time in UTC/GMT/ZULU/Timezone 0 and store 
it with 000 as milliseconds + Z for timezone Zulu 

Nonce is a random generated string 
*/
ASSIGN 
    dtZuluNow      = DATETIME-TZ(NOW,0)
    cCreated       = STRING(dtZuluNow, "9999-99-99THH:MM:SS") + ":000Z"
    cPasswordClear = "SECRET"
    cNonceB64      = BASE64-ENCODE(GENERATE-RANDOM-KEY)
    cNonce         = STRING(BASE64-DECODE(cNonceB64)).


RUN generatePassHashNonceClear( cNonce, cCreated, cPasswordClear, OUTPUT cPasswordDigest).

我知道的:

在10 000個請求中的9 500個中,這種方法效果很好。 但是失敗率為5%。 不幸的是,錯誤消息沒有幫助,所以我真正看到的只是登錄失敗。 Web服務提供商指出,由於摘要不正確,登錄被拒絕。

我做了什么:

為了測試摘要過程,我創建了一個小型python程序。 當我嘗試使用來自失敗登錄的in數據(即刻和時間戳記)時,確實會創建不同的摘要。 但是我不是Python程序員,因此該程序中很可能出了點問題(但這很奇怪,巧合的是,它也可以在所有情況下的95%中工作)。

這是python程序:

import hashlib

def createDigest(Nonce, Created, Password):
    "This function returns a digest"

    NonceB64 = Nonce.decode("base64","strict")

    pdgst = hashlib.sha1()
    pdgst.update(Password)
    PasswordDgst = pdgst.digest()


    FinalDgst = hashlib.sha1()
    FinalDgst.update(NonceB64)
    FinalDgst.update(Created)
    FinalDgst.update(PasswordDgst)

    FinalTxt = FinalDgst.digest().encode("base64","strict")
    print "Final digest : " + FinalTxt

    return

print "This digest is repeated in Progress OpenEdge"
createDigest("tGxF8+DAmJvQo93PNZt5Nw==", "2015-04-08T20:10:44:000Z", "SECRET")

print "This digest isn't repeated in Progress OpenEdge"
createDigest("XdcAW1TdTr+MLp4t0QkJ8g==", "2015-04-08T20:10:44:000Z", "SECRET")

我的真實密碼當然不是“ SECRET”,這使我相信錯誤與隨機數有關。 將密碼更改為“ SECRET”會使摘要有所不同,但此后仍然存在Progress和Python摘要之間的差異(上面的第一個示例在更改前后產生了相似的摘要,但第二個示例沒有發生變化)。

我對Progress Support有一個開放的案例,但是他們似乎和我一樣在這方面苦苦掙扎。

我已經在RHEL和Windows 7的OpenEdge 11.3.1和11.4中對此進行了測試,其行為保持不變。

回答我自己的問題以備將來參考:

正如@TomBascom指出的那樣,問題與代碼頁轉換有關,但實際錯誤實際上是在“鏈”中早於SHA消化。

cNonceB64      = BASE64-ENCODE(GENERATE-RANDOM-KEY)
cNonce         = STRING(BASE64-DECODE(cNonceB64))

在第二行中,只要生成的密鑰包含在iso8859-1和UTF-8之間不匹配的值,cNonce的值就會被銷毀。

一種簡單的解決方案是將cNonce變量更改為內存指針,然后重寫生成摘要的過程。

/* Optimistic, should really be based on current symmetric encryption algorithm */
SET-SIZE(mNonce) = 16.

ASSIGN
  mNonce    = GENERATE-RANDOM-KEY
  cNonceB64 = BASE64-ENCODE(mNonce).

然后生成密碼摘要的新過程:

PROCEDURE generateDigest:

/*------------------------------------------------------------------------------
  Purpose:     Generates a password hash for WS-Security
  Parameters:  <none>
  Notes:       
------------------------------------------------------------------------------*/

    DEFINE INPUT  PARAMETER mNonce     AS MEMPTR      NO-UNDO.
    DEFINE INPUT  PARAMETER pcCreated  AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcPassword AS CHARACTER   NO-UNDO.

    DEFINE OUTPUT PARAMETER pcHash     AS CHARACTER   NO-UNDO.

    DEFINE VARIABLE mBytes        AS MEMPTR      NO-UNDO.
    DEFINE VARIABLE mSHA1         AS MEMPTR      NO-UNDO.

    /* 
    Set size of mempointer, add 20 since we are adding the 20 byte 
    SHA1-DIGEST of the clear password in the end.
    */
    SET-SIZE(mBytes) = LENGTH(pcCreated) + 36. /* 16 + 20 = 36 */

    /* Put the decoded nonce first */
    PUT-BYTES(mBytes, 1) = mNonce.

    /* Add create time */
    PUT-STRING(mBytes, 17) = pcCreated. /* 16 + 1 = 17 */

    /* Set SHA1 returns a 20 byte raw string. */
    SET-SIZE(mSHA1) = 20.
    mSHA1 = SHA1-DIGEST(pcPassword).

    /* Add password, SHA1-digested (so we need to put bytes instead of a string */
    PUT-BYTES(mBytes, 17 + LENGTH(pcCreated)) = mSHA1. /* 16 + 1 = 17 */

    /* Create out-data in B64-encoded format */
    pcHash = STRING(BASE64-ENCODE(SHA1-DIGEST(mBytes))).

    /* Clean up mempointers */
    SET-SIZE(mBytes) = 0.
    SET-SIZE(mSHA1)  = 0.
    SET-SIZE(mNonce) = 0.
END PROCEDURE.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM