From ca3a20a4136e08a63d8f98f05845eef236a71e1b Mon Sep 17 00:00:00 2001 From: Xi Zhang Date: Mon, 28 Aug 2023 23:17:17 -0500 Subject: [PATCH 1/2] Add placeholder for Sapphire security --- docs/dapp/sapphire/security.md | 7 +++++++ sidebarDapp.js | 1 + 2 files changed, 8 insertions(+) create mode 100644 docs/dapp/sapphire/security.md diff --git a/docs/dapp/sapphire/security.md b/docs/dapp/sapphire/security.md new file mode 100644 index 0000000000..c079cdad81 --- /dev/null +++ b/docs/dapp/sapphire/security.md @@ -0,0 +1,7 @@ +--- +description: Security recommendations for Sapphire +--- + +# Security + +Work in Progress \ No newline at end of file diff --git a/sidebarDapp.js b/sidebarDapp.js index e408f8c3df..c05f3e6777 100644 --- a/sidebarDapp.js +++ b/sidebarDapp.js @@ -23,6 +23,7 @@ const sidebars = { 'dapp/sapphire/gasless', 'dapp/sapphire/precompiles', 'dapp/sapphire/addresses', + 'dapp/sapphire/security', { type: 'link', label: 'TypeScript API', From 92586e7bdeafea5dc6394c1f2663911f441a24d3 Mon Sep 17 00:00:00 2001 From: Xi Zhang Date: Tue, 29 Aug 2023 15:33:49 -0500 Subject: [PATCH 2/2] Add snippets for storage I/O, ordering, and gas padding --- docs/dapp/sapphire/guide.mdx | 5 +- docs/dapp/sapphire/security.md | 113 ++++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/docs/dapp/sapphire/guide.mdx b/docs/dapp/sapphire/guide.mdx index e1bc50e82b..b7689b5aae 100644 --- a/docs/dapp/sapphire/guide.mdx +++ b/docs/dapp/sapphire/guide.mdx @@ -183,7 +183,10 @@ state encryption key from the Oasis key manager. Both the keys and values of the items stored in state are encrypted, but the size of either is *not* hidden. You app may need to pad state items to a constant length, or use other obfuscation. Observers may also be able to infer computation based on storage access patterns, -so you might need to obfuscate that, too. +so you may need to obfuscate that, too. See [Security chapter] for more +recommendations. + +[Security chapter]: ./security.md#storage-access-patterns :::danger Contract state leaks a fine-grained access pattern diff --git a/docs/dapp/sapphire/security.md b/docs/dapp/sapphire/security.md index c079cdad81..e9f869e050 100644 --- a/docs/dapp/sapphire/security.md +++ b/docs/dapp/sapphire/security.md @@ -1,7 +1,116 @@ --- -description: Security recommendations for Sapphire +description: "Secure dApps: Recipes for Confidentiality" --- # Security -Work in Progress \ No newline at end of file +This page is an ongoing work in progress to support confidential smart contract +development. At the moment we address safeguarding storage variable access +patterns and provide best practices for more secure orderings of error checking +to prevent leaking contract state. + +## Storage Access Patterns + +You can use a tool such as [hardhat-tracer] to examine the base EVM state +transitions under the hood. + +```shell npm2yarn +npm install -D hardhat-tracer +``` + +and add `hardhat-tracer` to your `config.ts` file, + +```typescript +import "hardhat-tracer" +``` + +in order to test and show call traces. + +```shell +npx hardhat test --vvv --opcodes SSTORE,SLOAD +``` + +You can also trace a particular transaction, once you know its hash. + +```shell +npx hardhat trace --hash 0xTransactionHash +``` + +For both [gas] usage and confidentiality purposes, we **recommend using +non-unique data size**. E.g. 64-byte value will still be distinct from a +128-byte value. + +:::caution Inference based on access patterns + +`SSTORE` keys from one transaction may be linked to `SLOAD` keys of another +transaction. + +::: + +## Order of Operations + +When handling errors, gas usage patterns not only can reveal the code path +taken, **but sometimes the balance of a user as well** (in the case of a diligent +attacker using binary search). + +```solidity +function transferFrom(address who, address to, uint amount) + external +{ + require( balances[who] >= amount ); + require( allowances[who][msg.sender] >= amount ); + // ... +} +``` + +Modifying the order of error checking can prevent the accidental disclosure of +balance information in the example above. + +```solidity +function transferFrom(address who, address to, uint amount) + external +{ + require( allowances[who][msg.sender] >= amount ); + require( balances[who] >= amount ); + // ... +} +``` + +## Gas Padding + +To prevent leaking information about a particular transaction, Sapphire +provides a [precompile] for dApp developers to **pad the amount of gas used +in a transaction**. + +```solidity +contract GasExample { + bytes32 tmp; + + function constantMath(bool doMath, uint128 padGasAmount) external { + if (doMath) { + bytes32 x; + + for (uint256 i = 0; i < 100; i++) { + x = keccak256(abi.encodePacked(x, tmp)); + } + + tmp = x; + } + + Sapphire.padGas(padGasAmount); + } +} +``` + +Both contract calls below should use the same amount of gas. Sapphire also +provides the precompile to return the gas [used] by the current transaction. + +```typescript +await contract.constantMath(true, 100000); +await contract.constantMath(false, 100000); +``` + +[gas]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html +[hardhat-tracer]: https://www.npmjs.com/package/hardhat-tracer +[precompile]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#padgas +[used]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#gasused