Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion java/src/main/java/org/tron/common/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public class Utils {

public static final int MIN_LENGTH = 2;
public static final int MAX_LENGTH = 14;
public static final String VERSION = " v4.9.6";
public static final String VERSION = " v4.9.9";
public static final String TRANSFER_METHOD_ID = "a9059cbb";

private static SecureRandom random = new SecureRandom();
Expand Down
9 changes: 9 additions & 0 deletions java/src/main/java/org/tron/walletcli/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.google.common.primitives.Longs;
Expand Down Expand Up @@ -125,6 +126,14 @@

public class Client {

static {
// fastjson 1.x honors the "@type" hint in JSON.parseObject/parseArray even when the target is a
// JSONObject, which is the entry point for autoType deserialization gadgets. wallet-cli feeds
// remote HTTP/WebSocket payloads (GasFree, multi-sign) into those calls and never relies on
// "@type" itself, so safe mode rejects the hint outright and removes the gadget surface.
ParserConfig.getGlobalInstance().setSafeMode(true);
}

private WalletApiWrapper walletApiWrapper = new WalletApiWrapper();
private static int retryTime = 3;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.tron.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.tron.api.GrpcAPI.TransactionExtention;
import org.tron.api.GrpcAPI.TransactionSignWeight;
import org.tron.protos.Protocol;
import org.tron.protos.contract.BalanceContract.TransferContract;
import org.tron.trident.proto.Chain;
import org.tron.trident.proto.Response;
import org.tron.walletcli.Client;

/**
* Transaction rendering runs protobuf output through JSON.parseObject, and a Transaction carries its
* contract in a protobuf Any. Safe mode rejects any payload containing "@type", so this guards that
* our JsonFormat never emits that key and transaction display keeps working.
*/
public class TransactionJsonSafeModeTest {

@BeforeClass
public static void enableSafeMode() throws Exception {
Class.forName(Client.class.getName());
}

private static Protocol.Transaction transferTransaction() {
TransferContract transfer = TransferContract.newBuilder()
.setOwnerAddress(ByteString.copyFrom(new byte[]{0x41, 0x01, 0x02, 0x03}))
.setToAddress(ByteString.copyFrom(new byte[]{0x41, 0x04, 0x05, 0x06}))
.setAmount(1_000_000L)
.build();
Protocol.Transaction.Contract contract = Protocol.Transaction.Contract.newBuilder()
.setType(Protocol.Transaction.Contract.ContractType.TransferContract)
.setParameter(Any.pack(transfer))
.build();
return Protocol.Transaction.newBuilder()
.setRawData(Protocol.Transaction.raw.newBuilder()
.setTimestamp(1_700_000_000_000L)
.addContract(contract))
.build();
}

@Test
public void printsTransactionWithProtobufAnyUnderSafeMode() {
JSONObject json = Utils.printTransactionToJSON(transferTransaction(), true);

Assert.assertNotNull(json);
Assert.assertFalse("JsonFormat must not emit an @type key", json.toJSONString().contains("@type"));
Assert.assertTrue(json.toJSONString().contains("contract"));
}

@Test
public void printsTransactionStringUnderSafeMode() {
String text = Utils.printTransaction(transferTransaction());

Assert.assertNotNull(text);
Assert.assertFalse(text.contains("@type"));
}

@Test
public void printsTransactionSignWeightUnderSafeMode() {
TransactionSignWeight signWeight = TransactionSignWeight.newBuilder()
.setTransaction(TransactionExtention.newBuilder()
.setTransaction(transferTransaction()))
.build();

String text = Utils.printTransactionSignWeight(signWeight);

Assert.assertNotNull(text);
Assert.assertFalse(text.contains("@type"));
}

@Test
public void printsTransactionApprovedListUnderSafeMode() throws Exception {
Response.TransactionApprovedList approved = Response.TransactionApprovedList.newBuilder()
.setTransaction(Response.TransactionExtention.newBuilder()
.setTransaction(Chain.Transaction.parseFrom(transferTransaction().toByteArray())))
.build();

String text = Utils.printTransactionApprovedList(approved);

Assert.assertNotNull(text);
Assert.assertFalse(text.contains("@type"));
}
}
43 changes: 43 additions & 0 deletions java/src/test/java/org/tron/walletcli/FastjsonSafeModeTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.tron.walletcli;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

public class FastjsonSafeModeTest {

@BeforeClass
public static void loadClient() throws Exception {
// Client's static initializer is what enables safe mode for the shipped binary.
Class.forName(Client.class.getName());
}

@Test
public void clientEnablesFastjsonSafeMode() {
Assert.assertTrue(ParserConfig.getGlobalInstance().isSafeMode());
}

@Test
public void safeModeRejectsAutoTypeHint() {
String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\","
+ "\"dataSourceName\":\"ldap://127.0.0.1:1389/exploit\",\"autoCommit\":true}";
try {
JSON.parseObject(payload);
Assert.fail("safe mode must reject the @type autoType hint");
} catch (JSONException e) {
Assert.assertTrue(e.getMessage(), e.getMessage().contains("safeMode"));
}
}

@Test
public void safeModeStillParsesOrdinaryPayloads() {
JSONObject parsed = JSON.parseObject("{\"address\":\"TXyz\",\"balance\":42}");

Assert.assertEquals("TXyz", parsed.getString("address"));
Assert.assertEquals(42, parsed.getIntValue("balance"));
}
}
Loading