fix!: Prevent API from accepting seed or public key for account (#4404)

The API would allow seeds (and public keys) to be used in place of
accounts at several locations in the API. For example, when calling
account_info, you could pass `"account": "foo"`. The string "foo" is
treated like a seed, so the method returns `actNotFound` (instead of
`actMalformed`, as most developers would expect). In the early days,
this was a convenience to make testing easier. However, it allows for
poor security practices, so it is no longer a good idea. Allowing a
secret or passphrase is now considered a bug. Previously, it was
controlled by the `strict` option on some methods. With this commit,
since the API does not interpret `account` as `seed`, the option
`strict` is no longer needed and is removed.

Removing this behavior from the API is a [breaking
change](https://xrpl.org/request-formatting.html#breaking-changes). One
could argue that it shouldn't be done without bumping the API version;
however, in this instance, there is no evidence that anyone is using the
API in the "legacy" way. Furthermore, it is a potential security hole,
as it allows users to send secrets to places where they are not needed,
where they could end up in logs, error messages, etc. There's no reason
to take such a risk with a seed/secret, since only the public address is
needed.

Resolves: #3329, #3330, #4337

BREAKING CHANGE: Remove non-strict account parsing (#3330)
This commit is contained in:
drlongle
2023-05-17 02:22:10 +02:00
committed by GitHub
parent 67238b9fa6
commit 78076a6903
20 changed files with 203 additions and 351 deletions

View File

@@ -56,11 +56,22 @@ class AccountCurrencies_test : public beast::unit_test::suite
result[jss::error_message] == "Missing field 'account'.");
}
{ // strict mode, invalid bitcoin token
{
Json::Value params;
params[jss::account] =
"llIIOO"; // these are invalid in bitcoin alphabet
params[jss::strict] = true;
auto const result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actMalformed");
BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
}
{
// Cannot use a seed as account
Json::Value params;
params[jss::account] = "Bob";
auto const result = env.rpc(
"json",
"account_currencies",

View File

@@ -53,7 +53,9 @@ public:
"{\"account\": "
"\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Disallowed seed.");
info[jss::result][jss::error_code] == rpcACT_MALFORMED);
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Account malformed.");
}
{
// account_info with an account that's not in the ledger.
@@ -61,10 +63,21 @@ public:
auto const info = env.rpc(
"json",
"account_info",
std::string("{ ") + "\"account\": \"" + bogie.human() + "\"}");
R"({ "account": ")" + bogie.human() + R"("})");
BEAST_EXPECT(
info[jss::result][jss::error_code] == rpcACT_NOT_FOUND);
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Account not found.");
}
{
// Cannot use a seed as account
auto const info =
env.rpc("json", "account_info", R"({"account": "foo"})");
BEAST_EXPECT(
info[jss::result][jss::error_code] == rpcACT_MALFORMED);
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Account malformed.");
}
}
// Test the "signer_lists" argument in account_info.

View File

@@ -53,7 +53,7 @@ public:
R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
RPC::make_error(rpcBAD_SEED)[jss::error_message]);
RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
}
Account const alice{"alice"};
{
@@ -239,7 +239,7 @@ public:
R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
RPC::make_error(rpcBAD_SEED)[jss::error_message]);
RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
}
{
// A negative limit should fail.
@@ -815,7 +815,7 @@ public:
R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
BEAST_EXPECT(
lines[jss::error][jss::message] ==
RPC::make_error(rpcBAD_SEED)[jss::error_message]);
RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
BEAST_EXPECT(
lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
BEAST_EXPECT(
@@ -1122,7 +1122,7 @@ public:
R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
BEAST_EXPECT(
lines[jss::error][jss::message] ==
RPC::make_error(rpcBAD_SEED)[jss::error_message]);
RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
BEAST_EXPECT(
lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
BEAST_EXPECT(

View File

@@ -131,7 +131,7 @@ public:
"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Disallowed seed.");
resp[jss::result][jss::error_message] == "Account malformed.");
}
// test error on account that's not in the ledger.
{

View File

@@ -248,15 +248,15 @@ public:
"json",
"account_offers",
jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::error] == "badSeed");
BEAST_EXPECT(jrr[jss::error] == "actMalformed");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Disallowed seed.");
BEAST_EXPECT(jrr[jss::error_message] == "Account malformed.");
}
{
// bogus account value
auto const jrr =
env.rpc("account_offers", "rNOT_AN_ACCOUNT")[jss::result];
auto const jrr = env.rpc(
"account_offers", Account("bogus").human())[jss::result];
BEAST_EXPECT(jrr[jss::error] == "actNotFound");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Account not found.");

View File

@@ -127,8 +127,8 @@ class NoRippleCheck_test : public beast::unit_test::suite
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "badSeed");
BEAST_EXPECT(result[jss::error_message] == "Disallowed seed.");
BEAST_EXPECT(result[jss::error] == "actMalformed");
BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
}
}

View File

@@ -56,14 +56,16 @@ class OwnerInfo_test : public beast::unit_test::suite
result.isMember(jss::accepted) &&
result.isMember(jss::current)))
{
BEAST_EXPECT(result[jss::accepted][jss::error] == "badSeed");
BEAST_EXPECT(
result[jss::accepted][jss::error] == "actMalformed");
BEAST_EXPECT(
result[jss::accepted][jss::error_message] ==
"Disallowed seed.");
BEAST_EXPECT(result[jss::current][jss::error] == "badSeed");
"Account malformed.");
BEAST_EXPECT(
result[jss::current][jss::error] == "actMalformed");
BEAST_EXPECT(
result[jss::current][jss::error_message] ==
"Disallowed seed.");
"Account malformed.");
}
}

View File

@@ -86,7 +86,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
__LINE__,
{"account_channels",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"},
"rD5MbavGfiSC5m7mkxy1FANuT7s3HxqpoF"},
RPCCallTestData::no_exception,
R"({
"method" : "account_channels",
@@ -94,13 +94,15 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"destination_account" : "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"
"destination_account" : "rD5MbavGfiSC5m7mkxy1FANuT7s3HxqpoF"
}
]
})"},
{"account_channels: account and ledger index.",
__LINE__,
{"account_channels", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "closed"},
{"account_channels",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"r9emE59aTWb85t64dAebKrxYMBTpzK5yR7"},
RPCCallTestData::no_exception,
R"({
"method" : "account_channels",
@@ -108,7 +110,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"destination_account" : "closed"
"destination_account" : "r9emE59aTWb85t64dAebKrxYMBTpzK5yR7"
}
]
})"},
@@ -186,7 +188,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"current",
"strict"},
"extra"},
RPCCallTestData::no_exception,
R"({
"method" : "account_channels",
@@ -218,7 +220,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
// account_currencies
// ----------------------------------------------------------
{"account_currencies: minimal.",
{"account_currencies: minimal 1.",
__LINE__,
{"account_currencies", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"},
RPCCallTestData::no_exception,
@@ -231,17 +233,16 @@ static RPCCallTestData const rpcCallTestArray[] = {
}
]
})"},
{"account_currencies: strict.",
{"account_currencies: minimal 2.",
__LINE__,
{"account_currencies", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "strict"},
{"account_currencies", "racb4o3DrdYxuCfyVa6vsLb7vgju9RFbBr"},
RPCCallTestData::no_exception,
R"({
"method" : "account_currencies",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
"account" : "racb4o3DrdYxuCfyVa6vsLb7vgju9RFbBr"
}
]
})"},
@@ -275,10 +276,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
})"},
{"account_currencies: current ledger.",
__LINE__,
{"account_currencies",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"strict"},
{"account_currencies", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "current"},
RPCCallTestData::no_exception,
R"({
"method" : "account_currencies",
@@ -286,8 +284,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"api_version" : %MAX_API_VER%,
"ledger_index" : "current",
"strict" : 1
"ledger_index" : "current"
}
]
})"},
@@ -312,8 +309,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
{"account_currencies",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"strict",
"spare"},
"spare1",
"spare2"},
RPCCallTestData::no_exception,
R"({
"method" : "account_currencies",
@@ -358,20 +355,6 @@ static RPCCallTestData const rpcCallTestArray[] = {
]
})",
},
{"account_currencies: floating point first argument.",
__LINE__,
{"account_currencies", "3.14159", "strict"},
RPCCallTestData::no_exception,
R"({
"method" : "account_currencies",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "3.14159",
"strict" : 1
}
]
})"},
// account_info
// ----------------------------------------------------------------
@@ -432,26 +415,9 @@ static RPCCallTestData const rpcCallTestArray[] = {
}
]
})"},
{"account_info: strict.",
{"account_info: with ledger index.",
__LINE__,
{"account_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "strict"},
RPCCallTestData::no_exception,
R"({
"method" : "account_info",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
}
]
})"},
{"account_info: with ledger index and strict.",
__LINE__,
{"account_info",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"validated",
"strict"},
{"account_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "validated"},
RPCCallTestData::no_exception,
R"({
"method" : "account_info",
@@ -459,8 +425,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"api_version" : %MAX_API_VER%,
"ledger_index" : "validated",
"strict" : 1
"ledger_index" : "validated"
}
]
})"},
@@ -485,8 +450,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
{"account_info",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"strict",
"extra"},
"extra1",
"extra2"},
RPCCallTestData::no_exception,
R"({
"method" : "account_info",
@@ -798,9 +763,9 @@ static RPCCallTestData const rpcCallTestArray[] = {
}
]
})"},
{"account_objects: strict.",
{"account_objects: with ledger index.",
__LINE__,
{"account_objects", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "strict"},
{"account_objects", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "validated"},
RPCCallTestData::no_exception,
R"({
"method" : "account_objects",
@@ -808,25 +773,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
}
]
})"},
{"account_objects: with ledger index and strict.",
__LINE__,
{"account_objects",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"validated",
"strict"},
RPCCallTestData::no_exception,
R"({
"method" : "account_objects",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"ledger_index" : "validated",
"strict" : 1
"ledger_index" : "validated"
}
]
})"},
@@ -853,8 +800,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
"account_objects",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"extra",
"strict",
"extra1",
"extra2",
},
RPCCallTestData::no_exception,
R"({
@@ -862,8 +809,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
}
]
})"},
@@ -876,7 +822,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"current",
"extra1",
"extra2",
"strict",
"extra3",
},
RPCCallTestData::no_exception,
R"({
@@ -884,8 +830,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
}
]
})"},
@@ -898,7 +843,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"extra1",
"extra2",
"extra3",
"strict",
"extra4",
},
RPCCallTestData::no_exception,
R"({
@@ -953,10 +898,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
// cannot currently occur because jvParseLedger() always returns true.
"account_objects: invalid ledger selection 2.",
__LINE__,
{"account_objects",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"no_ledger",
"strict"},
{"account_objects", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "no_ledger"},
RPCCallTestData::no_exception,
R"({
"method" : "account_objects",
@@ -964,8 +906,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"ledger_index" : 0,
"strict" : 1
"ledger_index" : 0
}
]
})",
@@ -1030,9 +971,9 @@ static RPCCallTestData const rpcCallTestArray[] = {
}
]
})"},
{"account_offers: strict.",
{"account_offers: with ledger index.",
__LINE__,
{"account_offers", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "strict"},
{"account_offers", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "validated"},
RPCCallTestData::no_exception,
R"({
"method" : "account_offers",
@@ -1040,25 +981,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
}
]
})"},
{"account_offers: with ledger index and strict.",
__LINE__,
{"account_offers",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"validated",
"strict"},
RPCCallTestData::no_exception,
R"({
"method" : "account_offers",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"ledger_index" : "validated",
"strict" : 1
"ledger_index" : "validated"
}
]
})"},
@@ -1081,21 +1004,17 @@ static RPCCallTestData const rpcCallTestArray[] = {
{// Note: I believe this _ought_ to be detected as too many arguments.
"account_offers: four arguments.",
__LINE__,
{
"account_offers",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"extra",
"strict",
},
{"account_offers",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"extra"},
RPCCallTestData::no_exception,
R"({
"method" : "account_offers",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
}
]
})"},
@@ -1107,7 +1026,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
"current",
"extra1",
"extra2",
"strict",
"extra3",
},
RPCCallTestData::no_exception,
R"({
@@ -1162,10 +1081,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
// cannot currently occur because jvParseLedger() always returns true.
"account_offers: invalid ledger selection 2.",
__LINE__,
{"account_offers",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"no_ledger",
"strict"},
{"account_offers", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "no_ledger"},
RPCCallTestData::no_exception,
R"({
"method" : "account_offers",
@@ -1173,8 +1089,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"ledger_index" : 0,
"strict" : 1
"ledger_index" : 0
}
]
})",
@@ -4429,26 +4344,9 @@ static RPCCallTestData const rpcCallTestArray[] = {
}
]
})"},
{"owner_info: strict.",
{"owner_info: with ledger index.",
__LINE__,
{"owner_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "strict"},
RPCCallTestData::no_exception,
R"({
"method" : "owner_info",
"params" : [
{
"api_version" : %MAX_API_VER%,
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"strict" : 1
}
]
})"},
{"owner_info: with ledger index and strict.",
__LINE__,
{"owner_info",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"validated",
"strict"},
{"owner_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "validated"},
RPCCallTestData::no_exception,
R"({
"method" : "owner_info",
@@ -4456,8 +4354,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"api_version" : %MAX_API_VER%,
"ledger_index" : "validated",
"strict" : 1
"ledger_index" : "validated"
}
]
})"},
@@ -4483,8 +4380,8 @@ static RPCCallTestData const rpcCallTestArray[] = {
"owner_info",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"current",
"extra",
"strict",
"extra1",
"extra2",
},
RPCCallTestData::no_exception,
R"({
@@ -4537,12 +4434,9 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
// Note: there is code in place to return rpcLGR_IDX_MALFORMED. That
// cannot currently occur because jvParseLedger() always returns true.
"owner_info: invalid ledger selection and strict.",
"owner_info: invalid ledger selection.",
__LINE__,
{"owner_info",
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"no_ledger",
"strict"},
{"owner_info", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "no_ledger"},
RPCCallTestData::no_exception,
R"({
"method" : "owner_info",
@@ -4550,8 +4444,7 @@ static RPCCallTestData const rpcCallTestArray[] = {
{
"account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"api_version" : %MAX_API_VER%,
"ledger_index" : 0,
"strict" : 1
"ledger_index" : 0
}
]
})",