Add security best practice sections (#14798)
(cherry picked from commit 60611ae8a0)
			
			
This commit is contained in:
		
				
					committed by
					
						
						Michael Vines
					
				
			
			
				
	
			
			
			
						parent
						
							0cd1cce588
						
					
				
				
					commit
					4a6c3a9331
				
			@@ -13,6 +13,7 @@ $ npm install
 | 
			
		||||
 | 
			
		||||
This command starts a local development server and open up a browser window.
 | 
			
		||||
Most changes are reflected live without having to restart the server.
 | 
			
		||||
(You might have to run build.sh first if you run into failures)
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ npm run start
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,39 @@ _assign_ account ownership, meaning changing owner to different program id. If
 | 
			
		||||
an account is not owned by a program, the program is only permitted to read its
 | 
			
		||||
data and credit the account.
 | 
			
		||||
 | 
			
		||||
## Verifying validity of unmodified, reference-only accounts
 | 
			
		||||
 | 
			
		||||
For security purposes, it is recommended that programs check the validity of any
 | 
			
		||||
account it reads but does not modify.
 | 
			
		||||
 | 
			
		||||
The security model enforces that an account's data can only be modified by the
 | 
			
		||||
account's `Owner` program.  Doing so allows the program to trust that the data
 | 
			
		||||
passed to them via accounts they own will be in a known and valid state.  The
 | 
			
		||||
runtime enforces this by rejecting any transaction containing a program that
 | 
			
		||||
attempts to write to an account it does not own.  But, there are also cases
 | 
			
		||||
where a program may merely read an account they think they own and assume the
 | 
			
		||||
data has only been written by themselves and thus is valid.  But anyone can
 | 
			
		||||
issues instructions to a program, and the runtime does not know that those
 | 
			
		||||
accounts are expected to be owned by the program.  Therefore a malicious user
 | 
			
		||||
could create accounts with arbitrary data and then pass these accounts to the
 | 
			
		||||
program in the place of a valid account.  The arbitrary data could be crafted in
 | 
			
		||||
a way that leads to unexpected or harmful program behavior.
 | 
			
		||||
 | 
			
		||||
To check an account's validity, the program should either check the account's
 | 
			
		||||
address against a known value or check that the account is indeed owned
 | 
			
		||||
correctly (usually owned by the program itself).
 | 
			
		||||
 | 
			
		||||
One example is when programs read a sysvar.  Unless the program checks the
 | 
			
		||||
address or owner, it's impossible to be sure whether it's a real and valid
 | 
			
		||||
sysvar merely by successful deserialization. Accordingly, the Solana SDK [checks
 | 
			
		||||
the sysvar's validity during
 | 
			
		||||
deserialization](https://github.com/solana-labs/solana/blob/a95675a7ce1651f7b59443eb146b356bc4b3f374/sdk/program/src/sysvar/mod.rs#L65).
 | 
			
		||||
 | 
			
		||||
If the program always modifies the account in question, the address/owner check
 | 
			
		||||
isn't required because modifying an unowned (could be the malicious account with
 | 
			
		||||
the wrong owner) will be rejected by the runtime, and the containing transaction
 | 
			
		||||
will be thrown out.
 | 
			
		||||
 | 
			
		||||
## Rent
 | 
			
		||||
 | 
			
		||||
Keeping accounts alive on Solana incurs a storage cost called _rent_ because the
 | 
			
		||||
 
 | 
			
		||||
@@ -171,6 +171,26 @@ that this method only supports fixed sized types. Token utilizes the
 | 
			
		||||
trait to encode/decode instruction data for both token instructions as well as
 | 
			
		||||
token account states.
 | 
			
		||||
 | 
			
		||||
### Multiple instructions in a single transaction
 | 
			
		||||
 | 
			
		||||
A transaction can contain instructions in any order.   This means a malicious
 | 
			
		||||
user could craft transactions that may pose instructions in an order that the
 | 
			
		||||
program has not been protected against.  Programs should be hardened to properly
 | 
			
		||||
and safely handle any possible instruction sequence.
 | 
			
		||||
 | 
			
		||||
One not so obvious example is account deinitialization.  Some programs may
 | 
			
		||||
attempt to deinitialize an account by setting its lamports to zero, with the
 | 
			
		||||
assumption that the runtime will delete the account.  This assumption may be
 | 
			
		||||
valid between transactions, but it is not between instructions or cross-program
 | 
			
		||||
invocations.  To harden against this, the program should also explicitly zero out the
 | 
			
		||||
account's data.
 | 
			
		||||
 | 
			
		||||
An example of where this could be a problem is if a token program, upon
 | 
			
		||||
transferring the token out of an account, sets the account's lamports to zero,
 | 
			
		||||
assuming it will be deleted by the runtime.  If the program does zero out the
 | 
			
		||||
account's data, a malicious user could trail this instruction with another that
 | 
			
		||||
transfers the tokens a second time.
 | 
			
		||||
 | 
			
		||||
## Signatures
 | 
			
		||||
 | 
			
		||||
Each transaction explicitly lists all account public keys referenced by the
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user