【问题标题】:generate hmac sha1 with unicode escaped payload, oracle plsql使用 unicode 转义有效负载生成 hmac sha1,oracle plsql
【发布时间】:2019-01-10 16:33:33
【问题描述】:

所以我有一个 ORDS 端点(Oracle Rest Data Services),它从 Facebook API 接收 JSON 有效负载,以及一个变量 X-Hub-Signature,它位于请求的标头中。

我必须验证收到的请求,所以我知道它来自 Facebook。

我必须生成一个哈希来接收有效载荷 (BLOB) 和一个 facebook 和我共享的密钥 (字符串) (app_secret),然后我将它与 X-Hub-Signature 的值进行比较,这样我就可以确认这是一个有效的请求。

问题是,Facebook 说: “请注意,我们使用有效负载的转义 unicode 版本生成签名,带有小写十六进制数字。如果您只是根据解码后的字节进行计算,您最终会得到不同的签名。例如,字符串 äöå 应该转义为\u00e4\u00f6\u00e5。”

到目前为止,我的哈希值与我收到的有效载荷相匹配,但我尝试使用那些 äöå 字符,但我无法确定它是否有效,因为所有 hmac 在线编码器看起来都不那么好,而且我也不知道不知道如何通过 unicode 转义它们(在在线编码器上)。

到目前为止我有这个:

FUNCTION validate_payload (p_x_hub_signature      in     varchar2,
                           p_json_payload         in     blob)
RETURN varchar2
IS
    v_app_secret        varchar2(4000) := '2f2f2f2f2f2f2f';
    l_mac               raw(10000);
    v_x_hub_signature   varchar2(4000);

BEGIN

    l_mac := dbms_crypto.mac (src => p_json_payload,
                              typ => dbms_crypto.hmac_sh1,
                              key => UTL_I18N.STRING_TO_RAW (v_app_secret, 'AL32UTF8'));

    v_x_hub_signature := 'sha1='||lower(l_mac);

    return v_x_hub_signature;      

END;

您能对此提供任何反馈吗? 是这样吗?

提前致谢,抱歉英语不好或解释不好!

【问题讨论】:

  • 如何处理字符串中的"\""\u"
  • BMP 之外的字符,即U+FFFF 之上的字符呢?
  • Java 工具 native2ascii 正是这种转义。但是你必须调用一个外部二进制文件,所以你不能在 PL/SQL 中使用它。

标签: oracle api unicode sha1 hmac


【解决方案1】:

这是一个 PL/SQL 解决方案。它比 Sentinel 的提议需要更少的编码,并且可能更清晰。

declare
    v_app_secret varchar2(100) := 'äaöå ab\ABC';
    escaped varchar2(100);
    item varchar2(6);
begin

    escaped := replace(regexp_replace(ASCIISTR(v_app_secret), '\\([[:xdigit:]]{4})', '\u\1'), '\u005C', '\\');

    for i in 1..regexp_count(escaped, '\\u[[:xdigit:]]{4}') loop
        item := regexp_substr(escaped, '\\u[[:xdigit:]]{4}', 1, i);
        escaped := replace(escaped, item, lower(item));        
    end loop;
    dbms_output.put_line(escaped);

end;


\u00e4a\u00f6\u00e5 ab\\ABC

假设\需要翻译成\\

【讨论】:

  • v_app_secret 不需要翻译,但 p_json_payload 需要。这种方法最终可能会对 regexp_substr 和 relplace 进行数千次(或更多)或冗余调用,而 `regexp_replace 函数的相对较短序列(如果需要将 \u005c 转换为 \,则为 25 或 26)可以在纯 SQL 中处理它.
  • 哇,谢谢 Wernfried Domscheit,我会试试你的方法!我真的很感谢你的帮助,非常感谢。我会尽快提供反馈。再次感谢您
【解决方案2】:

从@Wernfried Domscheit 使用ASCIISTRregexp_replace 的方法开始,它可以扩展到整个替换列表以获得小写版本:

with sample(str) as (
  select 'äöå ab\ABC' from dual
), patterns(ord, pat, rep) as (
  select 1, '\\A([[:xdigit:]]{3})', '\\a\1' from dual union all
  select 2, '\\B([[:xdigit:]]{3})', '\\b\1' from dual union all
  select 3, '\\C([[:xdigit:]]{3})', '\\c\1' from dual union all
  select 4, '\\D([[:xdigit:]]{3})', '\\d\1' from dual union all
  select 5, '\\E([[:xdigit:]]{3})', '\\e\1' from dual union all
  select 6, '\\F([[:xdigit:]]{3})', '\\f\1' from dual union all
  select 7, '\\([[:xdigit:]])A([[:xdigit:]]{2})', '\\\1a\2' from dual union all
  select 8, '\\([[:xdigit:]])B([[:xdigit:]]{2})', '\\\1b\2' from dual union all
  select 9, '\\([[:xdigit:]])C([[:xdigit:]]{2})', '\\\1c\2' from dual union all
  select 10, '\\([[:xdigit:]])D([[:xdigit:]]{2})', '\\\1d\2' from dual union all
  select 11, '\\([[:xdigit:]])E([[:xdigit:]]{2})', '\\\1e\2' from dual union all
  select 12, '\\([[:xdigit:]])F([[:xdigit:]]{2})', '\\\1f\2' from dual union all
  select 13, '\\([[:xdigit:]]{2})A([[:xdigit:]])', '\\\1a\2' from dual union all
  select 14, '\\([[:xdigit:]]{2})B([[:xdigit:]])', '\\\1b\2' from dual union all
  select 15, '\\([[:xdigit:]]{2})C([[:xdigit:]])', '\\\1c\2' from dual union all
  select 16, '\\([[:xdigit:]]{2})D([[:xdigit:]])', '\\\1d\2' from dual union all
  select 17, '\\([[:xdigit:]]{2})E([[:xdigit:]])', '\\\1e\2' from dual union all
  select 18, '\\([[:xdigit:]]{2})F([[:xdigit:]])', '\\\1f\2' from dual union all
  select 19, '\\([[:xdigit:]]{3})A', '\\\1a' from dual union all
  select 20, '\\([[:xdigit:]]{3})B', '\\\1b' from dual union all
  select 21, '\\([[:xdigit:]]{3})C', '\\\1c' from dual union all
  select 22, '\\([[:xdigit:]]{3})D', '\\\1d' from dual union all
  select 23, '\\([[:xdigit:]]{3})E', '\\\1e' from dual union all
  select 24, '\\([[:xdigit:]]{3})F', '\\\1f' from dual union all
  select 25, '\\([[:xdigit:]]{4})', '\u\1' from dual union all
  select 26, '\\u005c', '\\\\' from dual
), recur(ord, str, tr) as (
  select ord, str
       , REGEXP_REPLACE(asciistr(str), pat, rep)
    from sample
    join patterns
      on ord = 1
  union all
  select recur.ord+1, str
       , REGEXP_REPLACE(tr, pat, rep)
    from recur
    join patterns
      on patterns.ord = recur.ord + 1
)
select * from recur where ord = 26;

如果你想要一个 PL/SQL 函数来完成它,可以将一系列转换嵌套起来并放入一个函数中。如果您不希望 \u005c 的最终转换为 \ 只需删除外部 regexp_replace:

create or replace function Escape_Unicode(pCLOB clob) RETURN clob is
BEGIN
  return  regexp_replace(
            regexp_replace(
              regexp_replace(
                regexp_replace(
                  regexp_replace(
                    regexp_replace(
                      regexp_replace(
                        regexp_replace(
                          regexp_replace(
                            regexp_replace(
                              regexp_replace(
                                regexp_replace(
                                  regexp_replace(
                                    regexp_replace(
                                      regexp_replace(
                                        regexp_replace(
                                          regexp_replace(
                                            regexp_replace(
                                              regexp_replace(
                                                regexp_replace(
                                                  regexp_replace(
                                                    regexp_replace(
                                                      regexp_replace(
                                                        regexp_replace(
                                                          regexp_replace(
                                                            regexp_replace(
                                                              asciistr(pClOB)
                                                              , '\\A([[:xdigit:]]{3})'
                                                              , '\\a\1'
                                                            )
                                                            , '\\B([[:xdigit:]]{3})'
                                                            , '\\b\1'
                                                          )
                                                          , '\\C([[:xdigit:]]{3})'
                                                          , '\\c\1'
                                                        )
                                                        , '\\D([[:xdigit:]]{3})'
                                                        , '\\d\1'
                                                      )
                                                      , '\\E([[:xdigit:]]{3})'
                                                      , '\\e\1'
                                                    )
                                                    , '\\F([[:xdigit:]]{3})'
                                                    , '\\f\1'
                                                  )
                                                  , '\\([[:xdigit:]])A([[:xdigit:]]{2})'
                                                  , '\\\1a\2'
                                                )
                                                , '\\([[:xdigit:]])B([[:xdigit:]]{2})'
                                                , '\\\1b\2'
                                              )
                                              , '\\([[:xdigit:]])C([[:xdigit:]]{2})'
                                              , '\\\1c\2'
                                            )
                                            , '\\([[:xdigit:]])D([[:xdigit:]]{2})'
                                            , '\\\1d\2'
                                          )
                                          , '\\([[:xdigit:]])E([[:xdigit:]]{2})'
                                          , '\\\1e\2'
                                        )
                                        , '\\([[:xdigit:]])F([[:xdigit:]]{2})'
                                        , '\\\1f\2'
                                      )
                                      , '\\([[:xdigit:]]{2})A([[:xdigit:]])'
                                      , '\\\1a\2'
                                    )
                                    , '\\([[:xdigit:]]{2})B([[:xdigit:]])'
                                    , '\\\1b\2'
                                  )
                                  , '\\([[:xdigit:]]{2})C([[:xdigit:]])'
                                  , '\\\1c\2'
                                )
                                , '\\([[:xdigit:]]{2})D([[:xdigit:]])'
                                , '\\\1d\2'
                              )
                              , '\\([[:xdigit:]]{2})E([[:xdigit:]])'
                              , '\\\1e\2'
                            )
                            , '\\([[:xdigit:]]{2})F([[:xdigit:]])'
                            , '\\\1f\2'
                          )
                          , '\\([[:xdigit:]]{3})A'
                          , '\\\1a'
                        )
                        , '\\([[:xdigit:]]{3})B'
                        , '\\\1b'
                      )
                      , '\\([[:xdigit:]]{3})C'
                      , '\\\1c'
                    )
                    , '\\([[:xdigit:]]{3})D'
                    , '\\\1d'
                  )
                  , '\\([[:xdigit:]]{3})E'
                  , '\\\1e'
                )
                , '\\([[:xdigit:]]{3})F'
                , '\\\1f'
              )
              , '\\([[:xdigit:]]{4})'
              , '\u\1'
            )
            , '\\u005c'
            , '\\\\'
          );
end;
/
select escape_unicode('äöå ab\ABCd') from dual;

【讨论】:

    【解决方案3】:

    我刚刚意识到,我可能已经诱使您犯了错误。正如 Sentinel 所说,v_app_secret 不需要翻译,只需要翻译 p_json_payload,它是一个 BLOB。

    到目前为止,我想出了这个:你认为这没关系吗?我无法确定:/

    FUNCTION validate_payload (p_x_hub_signature      in     varchar2,
                               p_json_payload         in     blob)
    RETURN varchar2
    IS
        v_app_secret        varchar2(4000) := '3f2f2f2f23f23f23';
        l_mac               raw(10000);
        v_x_hub_signature   varchar2(4000);
    BEGIN
        l_mac := dbms_crypto.mac (src => UTL_I18N.STRING_TO_RAW (utl_raw.cast_to_varchar2 (p_json_payload),'AL32UTF8'),
                                  typ => dbms_crypto.hmac_sh1,
                                  key => UTL_I18N.STRING_TO_RAW (v_app_secret, 'AL32UTF8'));
    
        v_x_hub_signature := 'sha1='||lower(l_mac);
    
        dbms_output.put_line(v_x_hub_signature);
    
        return v_x_hub_signature;      
    
    END;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-01
      相关资源
      最近更新 更多