如何使用具有正确Headers和SHA512哈希令牌的Node生成正确的TOTP



最近分配给我的一个学校项目有一个编码挑战,我们必须完成。挑战有多个部分,最后一部分是上传到私人GitHub回购,并在特定条件下通过POST请求提交完成请求。

我已经成功完成了挑战的其他部分,并坚持提交请求。提交必须遵循以下规则:

构建您的解决方案请求

首先,构造一个JSON字符串,如下所示:

{

 nbsp nbsp;"github_url": "https://github.com/YOUR_ACCOUNT/GITHUB_REPOSITORY",

 nbsp nbsp;"contact_email": "YOUR_EMAIL"

}

YOUR_EMAIL中填写您的电子邮件地址,并在YOUR_ACCOUNT/GITHUB_REPOSITORY中填写包含您的解决方案的私人Github存储库。然后,使用JSON字符串作为正文部分,向以下URL发出HTTPPOST请求。

CHALLENGE_URL

内容类型

请求的Content-Type:必须为application/json

授权

URL受HTTP基本身份验证保护,RFC2617第2章对此进行了解释,因此您必须在POST请求中提供Authorization:header字段。

  • 对于HTTP基本身份验证的userid,请使用与JSON字符串中相同的电子邮件地址
  • 对于密码,提供符合RFC6238的10位基于时间的一次性密码TOTP

授权密码

要生成TOTP密码,您需要使用以下设置:

  • 您必须根据RFC6238生成正确的TOTP密码
  • TOTP的Time Step X为30秒。CCD_ 10为0
  • 使用HMAC-SHA-512作为哈希函数,而不是默认的HMAC-SHA-1
  • 令牌共享机密是用户ID后面跟着ASCII字符串值"APICHALLENGE"(不包括双引号(

共享机密示例

例如,如果用户ID是"email@example.com",则令牌共享机密是"email@example.comAPICHALLENGE"(不带引号(。

如果POST请求成功,服务器将返回HTTP状态代码200。

我试着非常仔细地遵循这个大纲,并以不同的方式测试我的工作。然而,我似乎做不好。我们应该从Node服务器后端发出请求。这就是我迄今为止所做的。我用npm init创建了一个新的npm项目,并安装了您将在下面的代码中看到的依赖项:

const axios = require('axios');
const base64 = require('base-64');
const utf8 = require('utf8');
const { totp } = require('otplib');

const reqJSON = 
{
github_url: GITHUB_URL,
contact_email: MY_EMAIL
}
const stringData = JSON.stringify(reqJSON);
const URL = CHALLENGE_URL;
const sharedSecret = reqJSON.contact_email + "APICHALLENGE";
totp.options = { digits: 10, algorithm: "sha512" }
const myTotp = totp.generate(sharedSecret);
const isValid = totp.check(myTotp, sharedSecret);
console.log("Token Info:", {myTotp, isValid});


const authStringUTF = reqJSON.contact_email + ":" + myTotp;
const bytes = utf8.encode(authStringUTF);
const encoded = base64.encode(bytes);

const createReq = async () =>
{
try 
{
// set the headers
const config = {
headers: {
'Content-Type': 'application/json',
"Authorization": "Basic " + encoded
}
};
console.log("Making req", {URL, reqJSON, config});
const res = await axios.post(URL, stringData, config);
console.log(res.data);
}
catch (err)
{
console.error(err.response.data);
}
};
createReq();

据我所知,我不确定自己在哪里犯了错误。我在理解这些要求时尽量小心谨慎。我简要查看了挑战概述的所有文件,并收集了在给定条件下正确生成TOTP所需的必要要求。

我发现npm包otplib可以通过我传递的选项满足这些要求。

然而,我的解决方案是不正确的。当我尝试提交解决方案时,我会收到错误消息"Invalid token, wrong code"。有人能帮我看看我做错了什么吗?

我真的不希望我所有的努力都是徒劳的,因为这是一个漫长的项目。

提前非常感谢您在这方面的时间和帮助。我非常感激。

otplib的Readme状态:

// TOTP defaults
{
// ...includes all HOTP defaults
createHmacKey: totpCreateHmacKey,
epoch: Date.now(),
step: 30,
window: 0,
}

因此epoch (T0)的默认值是Date.now(),这是RFC标准。任务描述定义T00

您需要将epoch的默认值更改为0:

totp.options = { digits: 10, algorithm: "sha512", epoch: 0 }

最新更新