bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 54쪽 중 37쪽
alances[msg.sender];
for (uint256 i = 0; i < amounts.length; i++) {
require(currentBalance + amounts[i] >= currentBalance, "Overflow in batch");
currentBalance += amounts[i];
}
balances[msg.sender] = currentBalance;
}
function balanceOf(address account) external view returns (uint256) {
return balances[account];
}
}
```
</details>
This secure contract prevents overflow/underflow attacks:
**Key Security Features:**
1. **Overflow/Underflow Checks:**
* `require(a + b >= a, "overflow")` - detects addition overflow
* `require(a >= b, "underflow")` - prevents subtraction underflow
* Checks happen BEFORE arithmetic operations
2. **Supply Cap Enforcement:**
* Actually enforces `MAX_SUPPLY` limit
* Prevents unlimited token creation
3. **Access Control:**
* Only owner can mint tokens
* Prevents unauthorized token creation
4. **Input Validation:**
* Checks for zero addresses and amounts
* Batch size limits prevent gas attacks
**How it prevents attacks:**
* All arithmetic operations are validated before execution
* Supply limits prevent economic manipulation
* Access controls prevent unauthorized minting
* Batch limits prevent gas-based attacks
**How Security Works:**
**Attack Prevention:**
* Overflow/underflow checks prevent arithmetic attacks
* Supply cap enforcement prevents unlimited token creation
* Access control restricts minting to owner only
* Input validation prevents edge cases
**Result:**
* All arithmetic operations are safe
* Economic model is protected
* Attacks are blocked before execution
#### Protection Methods (summary)
| Method | Solidity Version | Effectiveness | Gas Cost |
| ------------------- | ---------------- | ------------- | -------- |
| Built-in Protection | 0.8+ | Very High | Low |
| SafeMath Library | <0.8 | High | Medium |
| Manual Checks | Any | High | Low |
| Unchecked Blocks | 0.8+ (when safe) | N/A | Very Low |
***
## Prevention Strategies (Consolidated)
1. Reentrancy Prevention
* Primary: Checks-Effects-Interactions pattern
* Secondary: Reentrancy guards (e.g., OpenZeppelin ReentrancyGuard)
* Additional: Pull payments, limit gas forwarded, prefer transfer() for simple ETH sends
2. Access Control Best Practices
* Use battle-tested libraries: OpenZeppelin AccessControl, Ownable
* Implement clear role hierarchy and immutable owner
* Emit events for role changes and use multisig for critical roles
3. Integer Overflow Protection
* Use Solidity 0.8+ (automatic checks)
* Add explicit pre-operation checks where appropriate
* Enforce supply caps and input limits
* For legacy code, use SafeMath
4. General Principles
* Defense in depth: stack protections
* Fail securely: default to safe state on errors
* Principle of least privilege: minimal necessary permissions
* Thorough testing and professional audits before mainnet deployment
***
## Testing Vulnerabilities
Use these commands and steps to test examples in Remix (manual steps):
```bash
# Deploy vulnerable contract in Remix
# Deploy attacker contract and execute attack
# Observe behavior and balances
# Deploy secure version and verify attack fails
```
Verification steps:
1. Deploy vulnerable contract on testnet (Somnia Testnet recommended).
2. Attempt exploit using attacker contract.
3. Observe vulnerability in action.
4. Deploy secure version with protections.
5. Verify exploit fails against secure implementation.
You can successfully identify and exploit vulnerabilities in a controlled test environment and verify mitigations on secure contracts.
***
## Common Vulnerability Patterns
Red flags in code review:
* External calls before state updates
* Missing access control modifiers
* Unchecked arithmetic operations
* Missing input validation
* No event emissions for critical actions
* Hardcoded addresses or values
* Complex inheritance hierarchies
* Missing reentrancy protection
Security scanning tools:
| Tool | Type | Effectiveness | Cost |
| --------- | ------------------ | ------------- | ---- |
| Slither | Static Analysis | High | Free |
| MythX | Comprehensive | Very High | Paid |
| Securify | Academic | Medium | Free |
| Manticore | Symbolic Execution | High | Free |
***
## Additional Resources
* [SWC Registry](https://swcregistry.io/) - Smart Contract Weakness Classification
* [Consensys Security Best Practices](https://consensys.github.io/smart-contract-best-practices/)
***
✅ Verification: You can identify vulnerable patterns and understand how attacks work.
🎉 Congratulations! You've mastered the most critical smart contract vulnerabilities, prevention strategies and secure coding patterns.
# Audit Checklist
This Self-Review Audit Checklist is the mandatory, internal quality assurance process that every smart contract must undergo before deployment to any public or private blockchain environment. Its purpose is to catch common, critical, and complex security vulnerabilities early, significantly reducing the risk of exploits, financial loss, and costly post-deployment fixes.
This process consists of two primary phases: a Manual Pre-Deployment Checklist and Automated Static Analysis Tooling.
## Phase 1: Manual Pre-Deployment Checklist
The development team must manually review and verify that the contract adheres to the following security, logic, and best-practice requirements.
**1.1. Security Vulnerability Checks**
| Item | Requirement | Verification Steps |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Reentrancy Protection** | All functions that send Ether or tokens to external addresses must follow the Checks-Effects-Interactions pattern. | Verify that state variables are updated before any external calls are made. Use `transfer`/`send` methods or reentrancy guards where necessary. |
| **Access Control** | Critical state-changing functions (e.g., `setOwner`, `pause`, `upgrade`, `mint`) must be guarded by proper access modifiers (e.g., `onlyOwner`, `onlyRole`). | Check that function visibility is correctly set (e.g., `internal`, `external`, `private`). |
| **Integer Overflow/Underflow** | All arithmetic operations, especially those based on user input, must be safe. | For Solidity >= 0.8.0, verify the compiler's default overflow checks are not disabled. For older versions, ensure the use of SafeMath libraries. |
| **Denial-of-Service (DoS)** | Operations must not iterate over unbounded arrays or map sizes that could be arbitrarily inflated by a malicious user, leading to excessive gas costs. | Check all loops to ensure iteration counts are fixed or restricted. |
| **External Call Security** | All interactions with unknown or untrusted external contracts are handled safely. | Ensure that results of external calls are checked and fail gracefully if necessary. Use call wrappers to limit reentrancy risk. |
| **Visibility** | State variables and functions intended for internal use must be declared `private` or `internal`. | Review all function and variable declarations for accidental public exposure. |
**1.2. Logic and Functional Checks**
| Item | Requirement | Verification Steps |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Functional Specification** | The contract logic precisely matches the intended business logic and all requirements documented in the functional specification. | Verify contract against all use cases and edge cases defined in the project scope. |
| **State Transitions** | The contract's state (e.g., token balances, operational phase) transitions correctly and predictably. | Trace critical functions (`transfer`, `claim`, `lock`) to ensure state variables update correctly. |
| **Error Handling** | All potential failure points are handled gracefully with clear, descriptive error messages. | Ensure that `require()` or `revert()` statements are used everywhere necessary and that custom error codes are defined and leveraged. |
| **Event Emission** | All critical state changes and value transfers must emit an appropriate `Event` to allow for off-chain monitoring, indexing, and UI responsiveness. | Verify that an `Event` is emitted for every action that changes a user-facing state. |
## Phase 2: Automated Static Analysis Tools
Static analysis is a mandatory, automated review step that must be completed using approved tools before deployment.
**2.1. Mandatory Tooling**
The following static analysis tools must be executed against the final version of the smart contract code:
| Tool | Purpose | Output Review Requirement |
| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| [**Slither**](https://github.com/crytic/slither) | Detects various security vulnerabilities (e.g., reentrancy, unprotected calls, misuses of `msg.sender`) and code optimization issues. | Must be executed with all security and efficiency detectors enabled. |
| [**Mythril**](https://github.com/ConsenSysDiligence/mythril) | Performs symbolic execution to find potential execution paths that could lead to vulnerabilities (e.g., integer overflows, assertion failures). | Must be run using its security analysis modes (e.g., full scan, execution path analysis). |
| [**Solhint**](https://github.com/protofire/solhint) | Enforces code style and security best practices, ensuring clean and maintainable code. | Must pass all configured security and style rulesets without warnings. |
**2.2. Warning Triage and Sign-off**
<details>
<summary>High/Critical Severity Warnings</summary>
Any issue categorized as High or Critical by the static analysis tools must be fixed immediately. The deployment process cannot proceed until these are resolved and the tools run clean.
</details>
<details>
<summary>Medium/Low Severity Warnings</summary>
These must be reviewed by a lead developer. They must either be:
* Fixed: If the issue is a genuine vulnerability or best practice deviation.
* Justified: If the tool's warning is a false positive or the logic is intentionally implemented in that manner, a clear, documented justification must be added to a dedicated "Audit Waivers" log.
</details>
<details>
<summary>Report Retention</summary>
The final, clean static analysis reports must be saved and archived as part of the pre-deployment documentation.
</details>
{% hint style="success" %}
**Congratulations!** You've mastered the audit checklist for both manual and automatic process. Continue to learn prevention strategies and secure coding patterns.
{% endhint %}
# Node/Infra Security
## Secure RPC Key Management and Environment Configuration for Somnia Developers
This comprehensive guide teaches developers how to securely manage RPC keys, private keys, and environment variables when building applications on the Somnia blockchain. If you're deploying smart contracts, building dApps, or integrating with Somnia. Proper security practices are essential to protect your assets and maintain service reliability. By following this tutorial, you'll implement industry-standard security measures with practical code examples that seamlessly integrate into your development workflow.
## Prerequisites
Before starting this guide, ensure you have:
* Basic knowledge of blockchain development and EVM concepts
* Node.js (20+) installed
* A code editor (VS Code recommended)
* A Somnia wallet with Somnia Token (STT) for testing
* Familiarity with environment variables and package managers
* Basic understanding of Git and version control
## RPC Key Security Fundamentals
RPC (Remote Procedure Call) keys and endpoints allow your application to interact with the blockchain. Using them securely is paramount.
A publicly accessible key, especially one with write permissions, can be exploited by an attacker to drain wallets or cause network congestion.
#### Using Ankr Provider
❌ **Bad Practice:**
```javascript
// Do not call your api Provider directly in your script with the api-keys!
// Setup provider AnkrProvider
const provider = new AnkrProvider('https://rpc.ankr.com/somnia_testnet/your-private-key');
```
✅ **Good Practice:**
```javascript
// Create a .env file
SOMNIA_ANKR_RPC_URL=https://rpc.ankr.com/somnia_testnet/your-private-key
// Use environment variables
// Setup provider AnkrProvider
const provider = new AnkrProvider(process.env.SOMNIA_ANKR_RPC_URL);
```
## Environment Variable Management
#### Private RPC Endpoints
While public endpoints are convenient for basic queries, they are prone to unreliability and congestion during high-traffic events. **Private RPCs are premium services and perform significantly better than the public RPC**, offering more speed and reliability through dedicated connections.
```javascript
// Example configuration for private endpoint
const config = {
testnet: {
url: process.env.SOMNIA_TESTNET_RPC_URL,
accounts: [process.env.TESTNET_PRIVATE_KEY]
}
};
```
#### Environment Variable Best Practices
A .env file is a standard way to manage environment-specific configuration:
```bash
# .env file
SOMNIA_TESTNET_RPC_URL=https://rpc.ankr.com/somnia_testnet/your-private-key
TESTNET_PRIVATE_KEY=your_private_key_here
NODE_ENV=development
```
#### Never Commit .env Files
The .env file should be added to your .gitignore file.
```bash
# .gitignore
.env
.env.local
.env.*.local
node_modules/
dist/
```
#### Create Separate Environment Files
Use separate configuration files for different environments.
```bash
# Project structure
├── .env.example # Template file (safe to commit)
├── .env.development # Development secrets
├── .env.test # Test environment
├── .env.staging # Staging environment
└── .env.production # Production secrets (never commit)
```
```javascript
// config/environment.js
const dotenv = require('dotenv');
const path = require('path');
const environment = process.env.NODE_ENV || 'development';
const envFile = `.env.${environment}`;
dotenv.config({ path: path.resolve(process.cwd(), envFile) });
module.exports = {
rpcUrl: process.env.SOMNIA_RPC_URL,
privateKey: process.env.PRIVATE_KEY,
environment
};
```
#### Reference Keys in Code
Always reference environment variables rather than hardcoding sensitive keys.
```javascript
// utils/blockchain.js
const { ethers } = require('ethers');
const config = require('../config/environment');
class BlockchainService {
constructor() {
this.provider = new ethers.JsonRpcProvider(config.rpcUrl);
this.wallet = new ethers.Wallet(config.privateKey, this.provider);
}
async getBalance(address) {
return await this.provider.getBalance(address);
}
async sendTransaction(to, value) {
const tx = {
to,
value: ethers.parseEther(value.toString())
};
return await this.wallet.sendTransaction(tx);
}
}
module.exports = BlockchainService;
```
#### Environment Variable Testing for Applications
**Note:** This testing approach is designed for application projects only, not system-wide configurations.
```javascript
// test-env.js - For application projects only
require('dotenv').config();
const testEnvironmentVariables = () => {
const requiredVars = [
'SOMNIA_TESTNET_RPC_URL',
'TESTNET_PRIVATE_KEY'
];
const missing = requiredVars.filter(varName => !process.env[varName]);
if (missing.length > 0) {
console.error('Missing required environment variables:', missing);
process.exit(1);
}
console.log('All required environment variables are loaded');
};
testEnvironmentVariables();
```
## Implementation Examples
#### Complete Project Setup
```bash
# 1. Initialize project
npm init -y
npm install ethers dotenv
npm install -D nodemon
# 2. Create environment template
echo "SOMNIA_RPC_URL=https://rpc.ankr.com/somnia_testnet/your-key-here" > .env.example
echo "PRIVATE_KEY=your-private-key-here" >> .env.example
echo "CONTRACT_ADDRESS=0x..." >> .env.example
# 3. Add to .gitignore
echo ".env*" >> .gitignore
echo "!.env.example" >> .gitignore
```
#### Secure Contract Interaction
```javascript
// contracts/SomniaContract.js
const { ethers } = require('ethers');
const config = require('../config/environment');
class SomniaContract {
constructor(contractAddress, abi) {
this.provider = new ethers.JsonRpcProvider(config.rpcUrl);
this.wallet = new ethers.Wallet(config.privateKey, this.provider);
this.contract = new ethers.Contract(contractAddress, abi, this.wallet);
}
async safeCall(methodName, ...args) {
try {
// Estimate gas first
const gasEstimate = await this.contract[methodName].estimateGas(...args);
// Add 20% buffer
const gasLimit = gasEstimate * 120n / 100n;
const tx = await this.contract[methodName](...args, { gasLimit });
console.log(`Transaction sent: ${tx.hash}`);
const receipt = await tx.wait();
console.log(`Transaction confirmed: ${receipt.transactionHash}`);
return receipt;
} catch (error) {
console.error('Transaction failed:', error.message);
throw error;
}
}
}
module.exports = SomniaContract;
```
## RPC Key Management
#### IP Whitelisting
If your RPC provider supports it, restrict access to your API key by creating an allowlist of trusted IP addresses.
```bash
# Example: Configure IP allowlist in your provider dashboard
# Allowed IPs: 203.0.113.1, 203.0.113.2
# This ensures only requests from your servers can use the key
```
#### Key Rotation and Expiration
Regularly rotate your RPC keys and immediately revoke any that are no longer in use.
<details>
<summary>Manual key rotation implementation</summary>
```javascript
// Manual key rotation implementation
// Note: RPC providers typically require manual key generation through their dashboard
// This implementation helps manage the rotation process once you have new keys
const updateEnvironmentVariable = async (key, value) => {
// Update .env file or environment configuration
const fs = require('fs').promises;
const envPath = '.env';
try {
let envContent = await fs.readFile(envPath, 'utf8');
const regex = new RegExp(`^${key}=.*$`, 'm');
if (regex.test(envContent)) {
envContent = envContent.replace(regex, `${key}=${value}`);
} else {
envContent += `\n${key}=${value}`;
}
await fs.writeFile(envPath, envContent);
console.log(`Updated ${key} in environment file`);
} catch (error) {
console.error('Failed to update environment variable:', error);
throw error;
}
};
// Manual key rotation helper
const rotateApiKey = async (newKey) => {
try {
// Validate the new key format
if (!newKey || typeof newKey !== 'string') {
throw new Error('Invalid API key provided');
}
// Store old key for reference
const oldKey = process.env.SOMNIA_TESTNET_RPC_URL;
console.log('Rotating API key...');
// Update environment variable
await updateEnvironmentVariable('SOMNIA_TESTNET_RPC_URL', newKey);
console.log('API key rotated successfully');
console.log('Please manually revoke the old key in your RPC provider dashboard');
console.log('Old key (first 10 chars):', oldKey?.substring(0, 10) + '...');
} catch (error) {
console.error('Key rotation failed:', error);
}
};
// Key rotation reminder system
const setupRotationReminder = () => {
const NINETY_DAYS = 90 * 24 * 60 * 60 * 1000;
setInterval(() => {
console.log('\n🔑 SECURITY REMINDER: Consider rotating your RPC API keys');
console.log('1. Generate new key in your RPC provider dashboard');
console.log('2. Call rotateApiKey(newKey) with the new key');
console.log프로젝트로 돌아가기