8
.gitignore
vendido
Archivo normal
8
.gitignore
vendido
Archivo normal
@@ -0,0 +1,8 @@
|
||||
node_modules/
|
||||
*.log
|
||||
.env
|
||||
*.pem
|
||||
*.key
|
||||
test-results/
|
||||
coverage/
|
||||
.DS_Store
|
||||
385
PROJECT_SUMMARY.md
Archivo normal
385
PROJECT_SUMMARY.md
Archivo normal
@@ -0,0 +1,385 @@
|
||||
# ActivityPub Security PoC - Project Summary
|
||||
|
||||
## ✅ Project Complete
|
||||
|
||||
A comprehensive security testing toolkit for ActivityPub protocol implementations has been successfully created.
|
||||
|
||||
## 📦 What Was Built
|
||||
|
||||
### Core Components
|
||||
|
||||
1. **ActivityPub Client** (`src/activitypub-client.js`)
|
||||
- Full HTTP client for ActivityPub interactions
|
||||
- Send activities to inbox endpoints
|
||||
- Fetch from outbox endpoints
|
||||
- Fetch actor profiles
|
||||
- HTTP signature support (framework ready)
|
||||
- JSON-LD context handling
|
||||
- Activity creation helpers
|
||||
|
||||
2. **Security Testing Module** (`src/security-tester.js`)
|
||||
- Automated vulnerability testing
|
||||
- 6 test categories:
|
||||
- Cross-Site Scripting (XSS)
|
||||
- Server-Side Request Forgery (SSRF)
|
||||
- Object injection & type confusion
|
||||
- Signature bypass
|
||||
- Authorization issues
|
||||
- SQL/Command injection
|
||||
- Comprehensive reporting
|
||||
|
||||
3. **CLI Tool** (`src/cli.js`)
|
||||
- User-friendly command-line interface
|
||||
- 7 main commands:
|
||||
- `test-inbox` - Send activities to inbox
|
||||
- `test-outbox` - Fetch from outbox
|
||||
- `fetch-actor` - Get actor profiles
|
||||
- `security-scan` - Run automated security tests
|
||||
- `craft` - Create custom activities
|
||||
- `mock-server` - Start mock server
|
||||
- `interactive` - Interactive mode (planned)
|
||||
|
||||
4. **Mock Server** (`src/mock-server.js`)
|
||||
- Fully functional ActivityPub server simulation
|
||||
- Complete endpoint implementation:
|
||||
- WebFinger (/.well-known/webfinger)
|
||||
- Actor profiles (/users/:username)
|
||||
- Inbox (/users/:username/inbox)
|
||||
- Outbox (/users/:username/outbox)
|
||||
- Followers/Following collections
|
||||
- Shared inbox
|
||||
- Real-time security detection
|
||||
- Activity validation
|
||||
- Detailed logging
|
||||
|
||||
### Documentation
|
||||
|
||||
1. **README.md** - Project overview and quick start
|
||||
2. **QUICKSTART.md** - Command reference and common use cases
|
||||
3. **examples/USAGE.md** - Comprehensive usage guide with examples
|
||||
4. **docs/SECURITY_TESTING.md** - Security testing methodology
|
||||
5. **docs/ARCHITECTURE.md** - Technical architecture documentation
|
||||
|
||||
### Example Payloads
|
||||
|
||||
- `examples/create-note.json` - Basic Create activity
|
||||
- `examples/follow.json` - Follow activity
|
||||
- `examples/xss-payload.json` - XSS test vectors
|
||||
- `examples/ssrf-payload.json` - SSRF test vectors
|
||||
|
||||
### Testing
|
||||
|
||||
- `test.sh` - Automated test script demonstrating all features
|
||||
|
||||
## 🎯 Key Features
|
||||
|
||||
### Security Testing Capabilities
|
||||
|
||||
- **XSS Detection**: 7+ different XSS vectors including script tags, event handlers, JavaScript protocols
|
||||
- **SSRF Detection**: Tests for internal network access, cloud metadata, file protocols
|
||||
- **Injection Testing**: SQL injection, command injection, prototype pollution
|
||||
- **Authorization Testing**: Actor impersonation, unauthorized actions
|
||||
- **Comprehensive Reporting**: Colored console output, JSON export, detailed logs
|
||||
|
||||
### Mock Server Features
|
||||
|
||||
- **Real-time Detection**: Identifies security issues as they arrive
|
||||
- **Multiple Users**: Pre-configured alice and bob accounts
|
||||
- **Full Protocol Support**: Implements ActivityPub spec endpoints
|
||||
- **Educational**: Shows both vulnerable and secure patterns
|
||||
|
||||
### Clean Code Practices
|
||||
|
||||
- Modular architecture with separation of concerns
|
||||
- Comprehensive error handling
|
||||
- Async/await throughout
|
||||
- Well-commented code
|
||||
- Consistent coding style
|
||||
- Reusable components
|
||||
|
||||
## 🚀 How to Use
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
cd activitypub-security-poc
|
||||
npm install
|
||||
|
||||
# Start mock server (Terminal 1)
|
||||
npm run mock-server
|
||||
|
||||
# Test it (Terminal 2)
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
|
||||
# Send a test activity
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--content "Hello from security PoC!"
|
||||
|
||||
# Run security scan
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox
|
||||
```
|
||||
|
||||
### Run Automated Test Suite
|
||||
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
|
||||
## 📊 What You Can Test
|
||||
|
||||
### Against Mock Server (Safe)
|
||||
|
||||
- Test all security vectors
|
||||
- Learn ActivityPub protocol
|
||||
- Develop secure implementations
|
||||
- Training and education
|
||||
|
||||
### Against Your Own Instance (Authorized)
|
||||
|
||||
- Validate security controls
|
||||
- Test inbox processing
|
||||
- Verify signature requirements
|
||||
- Check content sanitization
|
||||
|
||||
### Against Third-Party Instances (With Permission Only)
|
||||
|
||||
- Security audits
|
||||
- Penetration testing
|
||||
- Vulnerability research
|
||||
- Responsible disclosure
|
||||
|
||||
## 🛡️ Security Tests Included
|
||||
|
||||
### 1. Cross-Site Scripting (XSS)
|
||||
|
||||
Tests if user content is properly escaped:
|
||||
- `<script>alert('XSS')</script>`
|
||||
- `<img src=x onerror=alert('XSS')>`
|
||||
- `javascript:alert('XSS')`
|
||||
- SVG-based XSS
|
||||
- Event handler injection
|
||||
|
||||
### 2. Server-Side Request Forgery (SSRF)
|
||||
|
||||
Tests URL validation in:
|
||||
- Image URLs
|
||||
- Object IDs
|
||||
- Profile URLs
|
||||
- Link previews
|
||||
|
||||
Targets:
|
||||
- Internal IPs (localhost, 127.0.0.1)
|
||||
- Cloud metadata (169.254.169.254)
|
||||
- File protocols (file://)
|
||||
|
||||
### 3. Object Injection
|
||||
|
||||
Tests JSON validation:
|
||||
- Multiple type values
|
||||
- Missing required fields
|
||||
- Prototype pollution (`__proto__`)
|
||||
- Constructor manipulation
|
||||
|
||||
### 4. Signature Bypass
|
||||
|
||||
Tests authentication:
|
||||
- Missing signatures
|
||||
- Invalid signatures
|
||||
- Forged signatures
|
||||
|
||||
### 5. Authorization
|
||||
|
||||
Tests access control:
|
||||
- Actor impersonation
|
||||
- Unauthorized deletions
|
||||
- Cross-account access
|
||||
|
||||
### 6. Injection Attacks
|
||||
|
||||
Tests input sanitization:
|
||||
- SQL injection patterns
|
||||
- Command injection
|
||||
- Template injection
|
||||
|
||||
## 📈 Example Output
|
||||
|
||||
### Security Scan Results
|
||||
|
||||
```
|
||||
============================================================
|
||||
SECURITY TEST REPORT
|
||||
============================================================
|
||||
Target: http://localhost:3000/users/alice/inbox
|
||||
Timestamp: 2025-11-16T...
|
||||
============================================================
|
||||
|
||||
XSS:
|
||||
------------------------------------------------------------
|
||||
❌ VULNERABLE - XSS: <script>alert("XSS")</script>
|
||||
❌ VULNERABLE - XSS: <img src=x onerror=alert("XSS")>
|
||||
✅ SAFE - XSS: javascript:alert("XSS")
|
||||
|
||||
SSRF:
|
||||
------------------------------------------------------------
|
||||
🚨 VULNERABLE - SSRF: http://localhost:8080
|
||||
🚨 VULNERABLE - SSRF: http://169.254.169.254/latest/meta-data/
|
||||
|
||||
============================================================
|
||||
SUMMARY: 4/15 potential vulnerabilities found
|
||||
============================================================
|
||||
```
|
||||
|
||||
### Mock Server Detection
|
||||
|
||||
```
|
||||
📥 Received activity for alice:
|
||||
{
|
||||
"type": "Create",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"content": "<script>alert('XSS')</script>"
|
||||
}
|
||||
}
|
||||
|
||||
🚨 Security issues detected:
|
||||
- Potential XSS detected: <script>alert('XSS')</script>
|
||||
```
|
||||
|
||||
## 🎓 Educational Value
|
||||
|
||||
This toolkit demonstrates:
|
||||
|
||||
- **ActivityPub Protocol**: Complete implementation of core endpoints
|
||||
- **HTTP Signatures**: Framework for signing and verification
|
||||
- **JSON-LD**: Proper context handling
|
||||
- **Security Best Practices**: Input validation, sanitization, access control
|
||||
- **Testing Methodology**: Systematic security testing approach
|
||||
- **Clean Architecture**: Modular, maintainable code structure
|
||||
|
||||
## 🔧 Extensibility
|
||||
|
||||
Easy to extend:
|
||||
|
||||
### Add New Security Tests
|
||||
|
||||
```javascript
|
||||
// In security-tester.js
|
||||
async testNewVulnerability(inboxUrl) {
|
||||
// Your test logic
|
||||
}
|
||||
```
|
||||
|
||||
### Add New CLI Commands
|
||||
|
||||
```javascript
|
||||
// In cli.js
|
||||
program
|
||||
.command('new-command')
|
||||
.action(async (options) => {
|
||||
// Your command logic
|
||||
});
|
||||
```
|
||||
|
||||
### Add Mock Server Endpoints
|
||||
|
||||
```javascript
|
||||
// In mock-server.js
|
||||
async handleNewEndpoint(req, res, path) {
|
||||
// Your endpoint logic
|
||||
}
|
||||
```
|
||||
|
||||
## 📚 Documentation Structure
|
||||
|
||||
- **README.md** - Start here
|
||||
- **QUICKSTART.md** - Command reference
|
||||
- **examples/USAGE.md** - Detailed examples
|
||||
- **docs/SECURITY_TESTING.md** - Testing methodology
|
||||
- **docs/ARCHITECTURE.md** - Technical details
|
||||
|
||||
## ⚠️ Important Disclaimers
|
||||
|
||||
### Legal
|
||||
|
||||
- For authorized testing only
|
||||
- Obtain permission before testing third-party systems
|
||||
- Comply with computer fraud and abuse laws
|
||||
- Respect responsible disclosure guidelines
|
||||
|
||||
### Ethical
|
||||
|
||||
- Do not exploit vulnerabilities
|
||||
- Do not disrupt services
|
||||
- Do not access unauthorized data
|
||||
- Report findings responsibly
|
||||
|
||||
## 🎯 Use Cases
|
||||
|
||||
### Development
|
||||
|
||||
- Test your ActivityPub implementation
|
||||
- Validate security controls
|
||||
- Learn the protocol
|
||||
|
||||
### Security Research
|
||||
|
||||
- Discover vulnerabilities
|
||||
- Develop proof of concepts
|
||||
- Conduct authorized penetration tests
|
||||
|
||||
### Education
|
||||
|
||||
- Teach ActivityPub security
|
||||
- Demonstrate attack vectors
|
||||
- Show defensive techniques
|
||||
|
||||
## 🚦 Project Status
|
||||
|
||||
✅ **Complete and Functional**
|
||||
|
||||
All core features implemented:
|
||||
- ✅ ActivityPub client
|
||||
- ✅ Security testing module
|
||||
- ✅ CLI interface
|
||||
- ✅ Mock server
|
||||
- ✅ Example payloads
|
||||
- ✅ Comprehensive documentation
|
||||
- ✅ Test script
|
||||
|
||||
## 🔮 Future Enhancements
|
||||
|
||||
Potential additions:
|
||||
|
||||
1. Full HTTP signature implementation with RSA keys
|
||||
2. WebFinger testing
|
||||
3. Media upload testing
|
||||
4. Rate limiting tests
|
||||
5. Interactive wizard mode
|
||||
6. HTML report generation
|
||||
7. CI/CD integration examples
|
||||
8. More payload variations
|
||||
|
||||
## 📞 Next Steps
|
||||
|
||||
1. **Explore**: Run `./test.sh` to see it in action
|
||||
2. **Learn**: Read the documentation
|
||||
3. **Test**: Start the mock server and experiment
|
||||
4. **Extend**: Add your own tests
|
||||
5. **Contribute**: Enhance the toolkit
|
||||
|
||||
## 🎉 Summary
|
||||
|
||||
A professional-grade security testing toolkit for ActivityPub with:
|
||||
|
||||
- **Clean, modular code**
|
||||
- **Comprehensive testing coverage**
|
||||
- **Real mock server**
|
||||
- **Detailed documentation**
|
||||
- **Easy to use and extend**
|
||||
- **Educational value**
|
||||
- **Production-ready structure**
|
||||
|
||||
Perfect for security testers, developers, and researchers working with ActivityPub and the Fediverse!
|
||||
168
QUICKSTART.md
Archivo normal
168
QUICKSTART.md
Archivo normal
@@ -0,0 +1,168 @@
|
||||
# ActivityPub Security PoC - Quick Reference
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
cd activitypub-security-poc
|
||||
npm install
|
||||
```
|
||||
|
||||
## Quick Commands
|
||||
|
||||
### Start Mock Server
|
||||
```bash
|
||||
npm run mock-server
|
||||
# or
|
||||
node src/cli.js mock-server --port 3000
|
||||
```
|
||||
|
||||
### Run Quick Test
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
|
||||
### Fetch Actor
|
||||
```bash
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
```
|
||||
|
||||
### Test Inbox
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--content "Test message"
|
||||
```
|
||||
|
||||
### Security Scan
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox
|
||||
```
|
||||
|
||||
### Craft Activity
|
||||
```bash
|
||||
node src/cli.js craft --type Create --object Note --content "Hello"
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Test Local Mastodon Instance
|
||||
```bash
|
||||
# Start mock server
|
||||
npm run mock-server
|
||||
|
||||
# In another terminal, send activity
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/create-note.json
|
||||
```
|
||||
|
||||
### Test XSS Vulnerability
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/xss-payload.json
|
||||
```
|
||||
|
||||
### Test SSRF Vulnerability
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/ssrf-payload.json
|
||||
```
|
||||
|
||||
### Full Security Audit
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--output results-$(date +%Y%m%d).json
|
||||
```
|
||||
|
||||
## Testing Against Real Instances
|
||||
|
||||
⚠️ **Get permission first!**
|
||||
|
||||
```bash
|
||||
# Fetch public data (usually allowed)
|
||||
node src/cli.js fetch-actor --target https://mastodon.social/@Gargron
|
||||
node src/cli.js test-outbox --target https://mastodon.social/@Gargron/outbox
|
||||
|
||||
# Testing inbox requires authorization
|
||||
node src/cli.js test-inbox \
|
||||
--target https://your-instance.example/users/you/inbox \
|
||||
--content "Test from security PoC"
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
activitypub-security-poc/
|
||||
├── src/
|
||||
│ ├── cli.js # Main CLI
|
||||
│ ├── activitypub-client.js # HTTP client
|
||||
│ ├── security-tester.js # Security tests
|
||||
│ └── mock-server.js # Mock server
|
||||
├── examples/
|
||||
│ ├── *.json # Sample payloads
|
||||
│ └── USAGE.md # Detailed usage
|
||||
└── docs/
|
||||
├── ARCHITECTURE.md # Architecture docs
|
||||
└── SECURITY_TESTING.md # Testing guide
|
||||
```
|
||||
|
||||
## Help Commands
|
||||
|
||||
```bash
|
||||
# Main help
|
||||
node src/cli.js --help
|
||||
|
||||
# Command-specific help
|
||||
node src/cli.js test-inbox --help
|
||||
node src/cli.js security-scan --help
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `--output` to save results to JSON
|
||||
- Use `--tests` to run specific security tests
|
||||
- Check mock server logs for detected vulnerabilities
|
||||
- Read USAGE.md and SECURITY_TESTING.md for details
|
||||
- Always test with permission
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start mock server
|
||||
npm run mock-server
|
||||
|
||||
# Terminal 2: Run tests
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
node src/cli.js test-inbox --target http://localhost:3000/users/alice/inbox --content "Hello"
|
||||
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||
|
||||
# Check Terminal 1 for server logs showing received activities and security issues
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Cannot find module"**: Run `npm install`
|
||||
|
||||
**"ECONNREFUSED"**: Start the mock server first
|
||||
|
||||
**"Command not found"**: Use `node src/cli.js` instead of just `cli.js`
|
||||
|
||||
**Timeout errors**: Check if target is reachable
|
||||
|
||||
## Security Reminder
|
||||
|
||||
This tool is for **authorized security testing only**. Use it to:
|
||||
- Test your own servers
|
||||
- Conduct authorized penetration tests
|
||||
- Learn about ActivityPub security
|
||||
- Develop secure implementations
|
||||
|
||||
Do NOT use it to:
|
||||
- Attack systems without permission
|
||||
- Exploit vulnerabilities
|
||||
- Disrupt services
|
||||
- Access unauthorized data
|
||||
76
README.md
Archivo normal
76
README.md
Archivo normal
@@ -0,0 +1,76 @@
|
||||
# ActivityPub Security PoC
|
||||
|
||||
A comprehensive security testing toolkit for ActivityPub protocol implementations.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔍 **Security Testing**: Test common vulnerabilities in ActivityPub implementations
|
||||
- 🌐 **Remote Testing**: Probe outbox and inbox endpoints across instances
|
||||
- 🎭 **Mock Server**: Simulated ActivityPub server for controlled testing
|
||||
- 📝 **JSON-LD Support**: Full ActivityPub JSON-LD context handling
|
||||
- 🔐 **HTTP Signatures**: Test signature verification and authentication
|
||||
- 🛡️ **Injection Testing**: XSS, SSRF, and object injection tests
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### CLI Commands
|
||||
|
||||
```bash
|
||||
# Test an inbox endpoint
|
||||
node src/cli.js test-inbox --target https://instance.example/users/alice/inbox --payload ./payloads/note.json
|
||||
|
||||
# Test an outbox endpoint
|
||||
node src/cli.js test-outbox --target https://instance.example/users/alice/outbox
|
||||
|
||||
# Run security scans
|
||||
node src/cli.js security-scan --target https://instance.example --tests xss,ssrf,injection
|
||||
|
||||
# Start mock server
|
||||
node src/cli.js mock-server --port 3000
|
||||
|
||||
# Craft custom activity
|
||||
node src/cli.js craft --type Create --object Note --content "Test message"
|
||||
```
|
||||
|
||||
### Mock Server
|
||||
|
||||
```bash
|
||||
npm run mock-server
|
||||
```
|
||||
|
||||
The mock server provides:
|
||||
- `/users/:username` - Actor endpoints
|
||||
- `/users/:username/inbox` - Inbox endpoint
|
||||
- `/users/:username/outbox` - Outbox endpoint
|
||||
- `/.well-known/webfinger` - WebFinger endpoint
|
||||
|
||||
## Security Tests
|
||||
|
||||
### 1. XSS Testing
|
||||
Tests for Cross-Site Scripting vulnerabilities in content fields.
|
||||
|
||||
### 2. SSRF Testing
|
||||
Tests Server-Side Request Forgery via malicious URLs.
|
||||
|
||||
### 3. Object Injection
|
||||
Tests for improper object type validation.
|
||||
|
||||
### 4. Signature Bypass
|
||||
Tests HTTP signature verification weaknesses.
|
||||
|
||||
### 5. Authorization Issues
|
||||
Tests for improper access control on private activities.
|
||||
|
||||
## Examples
|
||||
|
||||
See the `examples/` directory for sample payloads and test scenarios.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This tool is for authorized security testing only. Always obtain permission before testing third-party systems.
|
||||
208
TABLE_OF_CONTENTS.md
Archivo normal
208
TABLE_OF_CONTENTS.md
Archivo normal
@@ -0,0 +1,208 @@
|
||||
# ActivityPub Security PoC - Table of Contents
|
||||
|
||||
## 📖 Documentation Index
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. **[README.md](README.md)** - Project overview, features, and installation
|
||||
2. **[QUICKSTART.md](QUICKSTART.md)** - Quick reference for common commands
|
||||
3. **[PROJECT_SUMMARY.md](PROJECT_SUMMARY.md)** - Complete project summary and capabilities
|
||||
|
||||
### Detailed Guides
|
||||
|
||||
4. **[examples/USAGE.md](examples/USAGE.md)** - Comprehensive usage examples and workflows
|
||||
5. **[docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)** - Security testing methodology and best practices
|
||||
6. **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Technical architecture and design
|
||||
|
||||
## 📁 Source Code
|
||||
|
||||
### Main Components
|
||||
|
||||
- **[src/cli.js](src/cli.js)** - Command-line interface
|
||||
- **[src/activitypub-client.js](src/activitypub-client.js)** - ActivityPub HTTP client
|
||||
- **[src/security-tester.js](src/security-tester.js)** - Security testing module
|
||||
- **[src/mock-server.js](src/mock-server.js)** - Mock ActivityPub server
|
||||
|
||||
## 🧪 Examples & Tests
|
||||
|
||||
### Sample Payloads
|
||||
|
||||
- **[examples/create-note.json](examples/create-note.json)** - Basic Create activity
|
||||
- **[examples/follow.json](examples/follow.json)** - Follow activity
|
||||
- **[examples/xss-payload.json](examples/xss-payload.json)** - XSS test vectors
|
||||
- **[examples/ssrf-payload.json](examples/ssrf-payload.json)** - SSRF test vectors
|
||||
|
||||
### Test Scripts
|
||||
|
||||
- **[test.sh](test.sh)** - Automated test suite
|
||||
|
||||
## 🎯 Quick Navigation
|
||||
|
||||
### I want to...
|
||||
|
||||
#### Learn about the project
|
||||
→ Start with [README.md](README.md)
|
||||
→ Read [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) for complete overview
|
||||
|
||||
#### Get started quickly
|
||||
→ Follow [QUICKSTART.md](QUICKSTART.md)
|
||||
→ Run `./test.sh` to see it in action
|
||||
|
||||
#### Understand how to use it
|
||||
→ Read [examples/USAGE.md](examples/USAGE.md)
|
||||
→ Try the example commands
|
||||
|
||||
#### Learn security testing
|
||||
→ Read [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||
→ Review the test payloads in `examples/`
|
||||
|
||||
#### Understand the code
|
||||
→ Read [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||
→ Review source code in `src/`
|
||||
|
||||
#### Extend the toolkit
|
||||
→ Read extension points in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||
→ Look at existing implementations in `src/`
|
||||
|
||||
## 📋 Common Tasks
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
cd activitypub-security-poc
|
||||
npm install
|
||||
```
|
||||
See: [README.md](README.md#installation)
|
||||
|
||||
### Run Mock Server
|
||||
```bash
|
||||
npm run mock-server
|
||||
```
|
||||
See: [QUICKSTART.md](QUICKSTART.md#start-mock-server)
|
||||
|
||||
### Run Security Scan
|
||||
```bash
|
||||
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||
```
|
||||
See: [examples/USAGE.md](examples/USAGE.md#run-security-scans)
|
||||
|
||||
### Test Inbox
|
||||
```bash
|
||||
node src/cli.js test-inbox --target URL --content "message"
|
||||
```
|
||||
See: [QUICKSTART.md](QUICKSTART.md#test-inbox)
|
||||
|
||||
### Craft Activity
|
||||
```bash
|
||||
node src/cli.js craft --type Create --object Note --content "text"
|
||||
```
|
||||
See: [examples/USAGE.md](examples/USAGE.md#craft-custom-activities)
|
||||
|
||||
## 🔍 Find Information About...
|
||||
|
||||
### ActivityPub Protocol
|
||||
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) - Protocol implementation
|
||||
- [src/activitypub-client.js](src/activitypub-client.js) - Client code
|
||||
- [src/mock-server.js](src/mock-server.js) - Server implementation
|
||||
|
||||
### Security Testing
|
||||
- [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Methodology
|
||||
- [src/security-tester.js](src/security-tester.js) - Test implementation
|
||||
- [examples/*.json](examples/) - Test payloads
|
||||
|
||||
### Command-Line Usage
|
||||
- [QUICKSTART.md](QUICKSTART.md) - Quick reference
|
||||
- [examples/USAGE.md](examples/USAGE.md) - Detailed examples
|
||||
- [src/cli.js](src/cli.js) - CLI implementation
|
||||
|
||||
### Mock Server
|
||||
- [src/mock-server.js](src/mock-server.js) - Server code
|
||||
- [examples/USAGE.md](examples/USAGE.md#testing-workflow) - Usage guide
|
||||
- Run `node src/cli.js mock-server --help`
|
||||
|
||||
## 📚 Documentation by Audience
|
||||
|
||||
### For Security Testers
|
||||
1. [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Testing methodology
|
||||
2. [examples/USAGE.md](examples/USAGE.md) - Practical examples
|
||||
3. [QUICKSTART.md](QUICKSTART.md) - Command reference
|
||||
|
||||
### For Developers
|
||||
1. [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) - Code architecture
|
||||
2. [src/](src/) - Source code
|
||||
3. [README.md](README.md) - Setup and usage
|
||||
|
||||
### For Learners
|
||||
1. [README.md](README.md) - Overview
|
||||
2. [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) - What it does
|
||||
3. [examples/USAGE.md](examples/USAGE.md) - How to use it
|
||||
4. [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Security concepts
|
||||
|
||||
## 🗂️ Complete File Structure
|
||||
|
||||
```
|
||||
activitypub-security-poc/
|
||||
├── README.md # Project overview
|
||||
├── QUICKSTART.md # Quick reference
|
||||
├── PROJECT_SUMMARY.md # Complete summary
|
||||
├── TABLE_OF_CONTENTS.md # This file
|
||||
├── package.json # Dependencies
|
||||
├── .gitignore # Git ignore rules
|
||||
├── test.sh # Test script
|
||||
│
|
||||
├── src/ # Source code
|
||||
│ ├── cli.js # CLI interface
|
||||
│ ├── activitypub-client.js # AP client
|
||||
│ ├── security-tester.js # Security tests
|
||||
│ └── mock-server.js # Mock server
|
||||
│
|
||||
├── docs/ # Documentation
|
||||
│ ├── ARCHITECTURE.md # Technical docs
|
||||
│ └── SECURITY_TESTING.md # Testing guide
|
||||
│
|
||||
└── examples/ # Examples & payloads
|
||||
├── USAGE.md # Usage guide
|
||||
├── create-note.json # Sample Create
|
||||
├── follow.json # Sample Follow
|
||||
├── xss-payload.json # XSS tests
|
||||
└── ssrf-payload.json # SSRF tests
|
||||
```
|
||||
|
||||
## 🚀 Getting Started Path
|
||||
|
||||
**Complete Beginner:**
|
||||
1. Read [README.md](README.md)
|
||||
2. Run `npm install`
|
||||
3. Run `./test.sh`
|
||||
4. Read [QUICKSTART.md](QUICKSTART.md)
|
||||
5. Experiment with commands
|
||||
|
||||
**Security Tester:**
|
||||
1. Read [README.md](README.md)
|
||||
2. Read [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||
3. Review [examples/USAGE.md](examples/USAGE.md)
|
||||
4. Start testing with mock server
|
||||
|
||||
**Developer:**
|
||||
1. Read [README.md](README.md)
|
||||
2. Read [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||
3. Review source code in [src/](src/)
|
||||
4. Extend as needed
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
- Use `--help` with any command for detailed options
|
||||
- Start with mock server before testing real instances
|
||||
- Always get permission before testing third-party systems
|
||||
- Check the example payloads for testing ideas
|
||||
- Review mock server logs to see what it detects
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **Questions about usage?** → [examples/USAGE.md](examples/USAGE.md)
|
||||
- **Security testing questions?** → [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||
- **Code questions?** → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||
- **Quick help?** → [QUICKSTART.md](QUICKSTART.md)
|
||||
|
||||
---
|
||||
|
||||
**Happy Testing! 🛡️**
|
||||
408
docs/ARCHITECTURE.md
Archivo normal
408
docs/ARCHITECTURE.md
Archivo normal
@@ -0,0 +1,408 @@
|
||||
# ActivityPub Security PoC - Architecture
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
activitypub-security-poc/
|
||||
├── src/
|
||||
│ ├── cli.js # Command-line interface
|
||||
│ ├── activitypub-client.js # ActivityPub HTTP client
|
||||
│ ├── security-tester.js # Security testing module
|
||||
│ └── mock-server.js # Mock ActivityPub server
|
||||
├── examples/
|
||||
│ ├── create-note.json # Sample Create activity
|
||||
│ ├── follow.json # Sample Follow activity
|
||||
│ ├── xss-payload.json # XSS test payload
|
||||
│ ├── ssrf-payload.json # SSRF test payload
|
||||
│ └── USAGE.md # Usage examples
|
||||
├── docs/
|
||||
│ ├── ARCHITECTURE.md # This file
|
||||
│ └── SECURITY_TESTING.md # Security testing guide
|
||||
├── package.json
|
||||
├── README.md
|
||||
└── test.sh # Quick test script
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. ActivityPub Client (`activitypub-client.js`)
|
||||
|
||||
**Purpose**: Low-level HTTP client for ActivityPub interactions.
|
||||
|
||||
**Key Features**:
|
||||
- Send activities to inbox endpoints
|
||||
- Fetch from outbox endpoints
|
||||
- Fetch actor profiles
|
||||
- HTTP signature generation (for authenticated requests)
|
||||
- JSON-LD context handling
|
||||
- Activity creation helpers
|
||||
|
||||
**Main Methods**:
|
||||
```javascript
|
||||
class ActivityPubClient {
|
||||
sendToInbox(inboxUrl, activity, options)
|
||||
fetchOutbox(outboxUrl, options)
|
||||
fetchActor(actorUrl, options)
|
||||
signRequest(method, url, body)
|
||||
createActivity(type, object, additionalProps)
|
||||
createNote(content, additionalProps)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Security Tester (`security-tester.js`)
|
||||
|
||||
**Purpose**: Automated security testing framework.
|
||||
|
||||
**Key Features**:
|
||||
- XSS vulnerability testing
|
||||
- SSRF vulnerability testing
|
||||
- Object injection testing
|
||||
- Signature bypass testing
|
||||
- Authorization testing
|
||||
- SQL/Command injection testing
|
||||
|
||||
**Main Methods**:
|
||||
```javascript
|
||||
class SecurityTester {
|
||||
testXSS(inboxUrl)
|
||||
testSSRF(inboxUrl)
|
||||
testObjectInjection(inboxUrl)
|
||||
testSignatureBypass(inboxUrl)
|
||||
testAuthorization(actorUrl, inboxUrl)
|
||||
testInjection(inboxUrl)
|
||||
runAllTests(targetUrl, options)
|
||||
generateReport(results)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. CLI (`cli.js`)
|
||||
|
||||
**Purpose**: User-friendly command-line interface.
|
||||
|
||||
**Commands**:
|
||||
- `test-inbox` - Send activities to inbox
|
||||
- `test-outbox` - Fetch from outbox
|
||||
- `fetch-actor` - Get actor profile
|
||||
- `security-scan` - Run security tests
|
||||
- `craft` - Create custom activities
|
||||
- `mock-server` - Start mock server
|
||||
|
||||
### 4. Mock Server (`mock-server.js`)
|
||||
|
||||
**Purpose**: Simulated ActivityPub server for testing.
|
||||
|
||||
**Key Features**:
|
||||
- Full ActivityPub endpoint simulation
|
||||
- WebFinger support
|
||||
- Activity validation
|
||||
- Security issue detection and logging
|
||||
- Multiple mock users (alice, bob)
|
||||
|
||||
**Endpoints**:
|
||||
- `/.well-known/webfinger` - WebFinger
|
||||
- `/users/:username` - Actor profiles
|
||||
- `/users/:username/inbox` - User inbox
|
||||
- `/users/:username/outbox` - User outbox
|
||||
- `/users/:username/followers` - Followers collection
|
||||
- `/users/:username/following` - Following collection
|
||||
- `/inbox` - Shared inbox
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Sending an Activity
|
||||
|
||||
```
|
||||
User Command
|
||||
↓
|
||||
CLI (cli.js)
|
||||
↓
|
||||
ActivityPubClient.sendToInbox()
|
||||
↓
|
||||
HTTP POST with JSON-LD payload
|
||||
↓
|
||||
Target Server (or Mock Server)
|
||||
↓
|
||||
Response (status, headers, body)
|
||||
↓
|
||||
Display to User
|
||||
```
|
||||
|
||||
### Security Scan
|
||||
|
||||
```
|
||||
User Command
|
||||
↓
|
||||
CLI (cli.js)
|
||||
↓
|
||||
SecurityTester.runAllTests()
|
||||
↓
|
||||
Multiple Test Methods (XSS, SSRF, etc.)
|
||||
↓
|
||||
ActivityPubClient.sendToInbox() for each payload
|
||||
↓
|
||||
Collect responses
|
||||
↓
|
||||
Analyze for vulnerabilities
|
||||
↓
|
||||
Generate Report
|
||||
↓
|
||||
Display to User
|
||||
```
|
||||
|
||||
### Mock Server Request Handling
|
||||
|
||||
```
|
||||
HTTP Request
|
||||
↓
|
||||
MockActivityPubServer.handleRequest()
|
||||
↓
|
||||
Route to appropriate handler
|
||||
↓
|
||||
Validate activity (if POST)
|
||||
↓
|
||||
Perform security checks
|
||||
↓
|
||||
Log detected issues
|
||||
↓
|
||||
Store activity (if valid)
|
||||
↓
|
||||
Return response
|
||||
```
|
||||
|
||||
## Security Testing Methodology
|
||||
|
||||
### 1. Test Case Design
|
||||
|
||||
Each security test:
|
||||
1. Creates a malicious payload
|
||||
2. Sends it to the target endpoint
|
||||
3. Analyzes the response
|
||||
4. Determines if vulnerability exists based on:
|
||||
- Response status (200/202 = potential issue)
|
||||
- Error messages
|
||||
- Behavior changes
|
||||
|
||||
### 2. Payload Categories
|
||||
|
||||
**XSS Payloads**:
|
||||
- Script tags
|
||||
- Event handlers
|
||||
- JavaScript protocols
|
||||
- SVG-based vectors
|
||||
- Encoded payloads
|
||||
|
||||
**SSRF Payloads**:
|
||||
- Internal IPs (localhost, 127.0.0.1)
|
||||
- Cloud metadata endpoints
|
||||
- File protocol URLs
|
||||
- IPv6 localhost
|
||||
- DNS rebinding targets
|
||||
|
||||
**Injection Payloads**:
|
||||
- SQL injection patterns
|
||||
- Command injection sequences
|
||||
- Prototype pollution attempts
|
||||
- Path traversal strings
|
||||
|
||||
### 3. Validation Logic
|
||||
|
||||
The mock server demonstrates proper validation:
|
||||
|
||||
```javascript
|
||||
// Activity validation
|
||||
validateActivity(activity) {
|
||||
- Check for required fields
|
||||
- Validate @context
|
||||
- Verify actor field
|
||||
- Return validation result
|
||||
}
|
||||
|
||||
// Security checks
|
||||
performSecurityChecks(activity) {
|
||||
- Scan for XSS patterns
|
||||
- Check for SSRF attempts
|
||||
- Detect prototype pollution
|
||||
- Identify SQL injection patterns
|
||||
- Return list of issues
|
||||
}
|
||||
```
|
||||
|
||||
## HTTP Signatures (Planned)
|
||||
|
||||
Future versions will implement full HTTP signature support:
|
||||
|
||||
```
|
||||
1. Generate RSA key pair
|
||||
2. Include public key in actor profile
|
||||
3. Sign requests with private key
|
||||
4. Verify signatures on mock server
|
||||
5. Test signature bypass scenarios
|
||||
```
|
||||
|
||||
## Extension Points
|
||||
|
||||
### Adding New Security Tests
|
||||
|
||||
1. Add test method to `SecurityTester`:
|
||||
```javascript
|
||||
async testNewVulnerability(inboxUrl) {
|
||||
const payloads = [...];
|
||||
const results = [];
|
||||
|
||||
for (const payload of payloads) {
|
||||
// Create activity with payload
|
||||
// Send to inbox
|
||||
// Analyze response
|
||||
results.push({...});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
```
|
||||
|
||||
2. Integrate into `runAllTests()`:
|
||||
```javascript
|
||||
if (!options.tests || options.tests.includes('newvuln')) {
|
||||
allResults.tests.newVuln = await this.testNewVulnerability(targetUrl);
|
||||
}
|
||||
```
|
||||
|
||||
### Adding New CLI Commands
|
||||
|
||||
1. Add command to `cli.js`:
|
||||
```javascript
|
||||
program
|
||||
.command('new-command')
|
||||
.description('Description')
|
||||
.option('-f, --flag <value>', 'Option')
|
||||
.action(async (options) => {
|
||||
// Implementation
|
||||
});
|
||||
```
|
||||
|
||||
### Extending Mock Server
|
||||
|
||||
1. Add new endpoint handler:
|
||||
```javascript
|
||||
async handleNewEndpoint(req, res, path) {
|
||||
// Handle request
|
||||
this.sendJSON(res, data);
|
||||
}
|
||||
```
|
||||
|
||||
2. Add route in `handleRequest()`:
|
||||
```javascript
|
||||
if (path.match(/^\/new-endpoint$/)) {
|
||||
await this.handleNewEndpoint(req, res, path);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Code Organization
|
||||
|
||||
- **Separation of Concerns**: Client, tester, CLI, and server are separate modules
|
||||
- **Reusability**: Core client can be used independently
|
||||
- **Extensibility**: Easy to add new tests or commands
|
||||
- **Clean Code**: Well-commented, readable, maintainable
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Graceful error handling in all HTTP requests
|
||||
- Informative error messages
|
||||
- Non-blocking errors (continue testing on failure)
|
||||
|
||||
### Logging
|
||||
|
||||
- Clear console output with color coding
|
||||
- Structured JSON output for results
|
||||
- Detailed mock server logs for debugging
|
||||
|
||||
### Testing Philosophy
|
||||
|
||||
- **Defense in Depth**: Test multiple vulnerability types
|
||||
- **Real-world Scenarios**: Payloads based on actual attacks
|
||||
- **Responsible Testing**: Tools designed for authorized testing only
|
||||
- **Educational**: Code demonstrates both vulnerabilities and mitigations
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
|
||||
1. **Full HTTP Signature Support**
|
||||
- RSA key generation
|
||||
- Signature creation and verification
|
||||
- Key rotation testing
|
||||
|
||||
2. **WebFinger Testing**
|
||||
- Account discovery
|
||||
- Resource validation
|
||||
- SSRF via WebFinger
|
||||
|
||||
3. **Media Upload Testing**
|
||||
- File upload vulnerabilities
|
||||
- Content-Type confusion
|
||||
- Malicious file detection bypass
|
||||
|
||||
4. **Rate Limiting Tests**
|
||||
- Concurrent request flooding
|
||||
- Activity spam detection
|
||||
- Resource exhaustion
|
||||
|
||||
5. **Interactive Mode**
|
||||
- Step-by-step testing wizard
|
||||
- Real-time response analysis
|
||||
- Guided security audits
|
||||
|
||||
6. **CI/CD Integration**
|
||||
- GitHub Actions workflow
|
||||
- Automated regression testing
|
||||
- Security benchmarking
|
||||
|
||||
7. **Reporting**
|
||||
- HTML report generation
|
||||
- PDF export
|
||||
- Vulnerability database integration
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Async Operations**: All HTTP requests are asynchronous
|
||||
- **Timeout Handling**: Configurable timeouts prevent hanging
|
||||
- **Resource Management**: Proper cleanup of connections
|
||||
- **Scalability**: Can test multiple endpoints in parallel
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Tool Security
|
||||
|
||||
- No sensitive data storage
|
||||
- No persistent state by default
|
||||
- Safe defaults (localhost, low timeout)
|
||||
- Clear warnings about authorized testing
|
||||
|
||||
### Mock Server Security
|
||||
|
||||
- Intentionally logs security issues (for demonstration)
|
||||
- Does not execute malicious payloads
|
||||
- Sandboxed environment
|
||||
- No real persistence
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **commander**: CLI argument parsing
|
||||
- **node-fetch**: HTTP client
|
||||
- **chalk**: Terminal colors
|
||||
- **jsonld**: JSON-LD processing
|
||||
- **http-signature**: HTTP signature support (planned)
|
||||
|
||||
All dependencies are well-maintained and security-audited.
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
When extending this project:
|
||||
|
||||
1. **Follow the architecture**: Keep separation of concerns
|
||||
2. **Add tests**: Include example payloads
|
||||
3. **Document**: Update this file and other docs
|
||||
4. **Clean code**: Follow existing style
|
||||
5. **Security first**: Consider implications of new features
|
||||
345
docs/SECURITY_TESTING.md
Archivo normal
345
docs/SECURITY_TESTING.md
Archivo normal
@@ -0,0 +1,345 @@
|
||||
# Security Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the security testing methodology and test cases for ActivityPub implementations.
|
||||
|
||||
## Security Test Categories
|
||||
|
||||
### 1. Cross-Site Scripting (XSS)
|
||||
|
||||
**Objective**: Identify if user-supplied content is properly sanitized before display.
|
||||
|
||||
**Test Cases**:
|
||||
- Script tag injection: `<script>alert('XSS')</script>`
|
||||
- Event handler injection: `<img src=x onerror=alert('XSS')>`
|
||||
- JavaScript protocol: `javascript:alert('XSS')`
|
||||
- SVG-based XSS: `<svg/onload=alert('XSS')>`
|
||||
- Encoded payloads: `<script>alert('XSS')</script>`
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- Content rendered without HTML escaping
|
||||
- Markdown/rich text processing vulnerabilities
|
||||
- URL handling in attachment previews
|
||||
|
||||
### 2. Server-Side Request Forgery (SSRF)
|
||||
|
||||
**Objective**: Test if the server can be tricked into making requests to internal resources.
|
||||
|
||||
**Test Cases**:
|
||||
- Internal network: `http://localhost:8080`, `http://127.0.0.1`
|
||||
- Cloud metadata: `http://169.254.169.254/latest/meta-data/`
|
||||
- IPv6 localhost: `http://[::1]:8080`
|
||||
- File protocol: `file:///etc/passwd`
|
||||
- DNS rebinding attacks
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- Fetching remote avatars/images without validation
|
||||
- Link previews/unfurling
|
||||
- WebFinger lookups without URL validation
|
||||
|
||||
### 3. Object Injection & Type Confusion
|
||||
|
||||
**Objective**: Test object validation and type handling.
|
||||
|
||||
**Test Cases**:
|
||||
- Multiple type values: `"type": ["Note", "Delete"]`
|
||||
- Missing required fields
|
||||
- Prototype pollution: `__proto__` injection
|
||||
- Constructor manipulation
|
||||
- Unexpected nested objects
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- Weak JSON schema validation
|
||||
- Dynamic property assignment
|
||||
- Type coercion vulnerabilities
|
||||
|
||||
### 4. Authentication & Authorization
|
||||
|
||||
**Objective**: Verify proper access controls and signature verification.
|
||||
|
||||
**Test Cases**:
|
||||
- Missing HTTP signatures
|
||||
- Invalid/forged signatures
|
||||
- Actor impersonation
|
||||
- Unauthorized deletions
|
||||
- Private content access
|
||||
- Relay poisoning
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- Weak signature verification
|
||||
- Missing authorization checks
|
||||
- Confused deputy attacks
|
||||
|
||||
### 5. Injection Attacks
|
||||
|
||||
**Objective**: Test for command and SQL injection vulnerabilities.
|
||||
|
||||
**Test Cases**:
|
||||
- SQL injection: `' OR '1'='1`, `'; DROP TABLE--`
|
||||
- Command injection: `; ls -la`, `| whoami`, `$(uname -a)`
|
||||
- LDAP injection
|
||||
- Template injection
|
||||
- Path traversal: `../../etc/passwd`
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- Direct database queries with user input
|
||||
- System command execution
|
||||
- Template rendering with user content
|
||||
|
||||
### 6. Denial of Service (DoS)
|
||||
|
||||
**Objective**: Test resilience against resource exhaustion.
|
||||
|
||||
**Test Cases**:
|
||||
- Large payloads (MB-sized JSON)
|
||||
- Deeply nested objects
|
||||
- Circular references
|
||||
- Excessive followers/following counts
|
||||
- Rapid activity submission
|
||||
|
||||
**Vulnerable Scenarios**:
|
||||
- No rate limiting
|
||||
- Unbounded resource allocation
|
||||
- Inefficient parsing
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
### 1. Reconnaissance
|
||||
|
||||
```bash
|
||||
# Fetch actor profile
|
||||
node src/cli.js fetch-actor --target https://target.example/users/alice
|
||||
|
||||
# Check outbox
|
||||
node src/cli.js test-outbox --target https://target.example/users/alice/outbox
|
||||
```
|
||||
|
||||
### 2. Baseline Testing
|
||||
|
||||
```bash
|
||||
# Send valid activity
|
||||
node src/cli.js test-inbox \
|
||||
--target https://target.example/users/alice/inbox \
|
||||
--payload examples/create-note.json
|
||||
```
|
||||
|
||||
### 3. Automated Security Scan
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
node src/cli.js security-scan \
|
||||
--target https://target.example/users/alice/inbox \
|
||||
--output scan-results.json
|
||||
```
|
||||
|
||||
### 4. Manual Payload Testing
|
||||
|
||||
```bash
|
||||
# Test specific vulnerability
|
||||
node src/cli.js test-inbox \
|
||||
--target https://target.example/users/alice/inbox \
|
||||
--payload examples/xss-payload.json
|
||||
```
|
||||
|
||||
### 5. Analysis
|
||||
|
||||
Review logs, responses, and behavior:
|
||||
- HTTP status codes
|
||||
- Error messages
|
||||
- Server-side rendering
|
||||
- Database queries
|
||||
- Network traffic
|
||||
|
||||
## Responsible Disclosure
|
||||
|
||||
If you discover a vulnerability:
|
||||
|
||||
1. **Do not exploit** beyond proof-of-concept
|
||||
2. **Document** the issue thoroughly
|
||||
3. **Report privately** to the maintainers
|
||||
4. **Allow time** for fixes (typically 90 days)
|
||||
5. **Coordinate** public disclosure
|
||||
|
||||
## Common Vulnerabilities in ActivityPub
|
||||
|
||||
### 1. Inadequate Input Validation
|
||||
|
||||
```javascript
|
||||
// Vulnerable
|
||||
app.post('/inbox', (req, res) => {
|
||||
const activity = req.body;
|
||||
db.query(`INSERT INTO activities VALUES ('${activity.id}')`); // SQL injection
|
||||
});
|
||||
|
||||
// Secure
|
||||
app.post('/inbox', (req, res) => {
|
||||
const activity = req.body;
|
||||
if (!validateActivitySchema(activity)) {
|
||||
return res.status(400).send('Invalid activity');
|
||||
}
|
||||
db.query('INSERT INTO activities VALUES (?)', [activity.id]);
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Missing Signature Verification
|
||||
|
||||
```javascript
|
||||
// Vulnerable
|
||||
app.post('/inbox', (req, res) => {
|
||||
// No signature check
|
||||
processActivity(req.body);
|
||||
});
|
||||
|
||||
// Secure
|
||||
app.post('/inbox', async (req, res) => {
|
||||
if (!await verifyHTTPSignature(req)) {
|
||||
return res.status(401).send('Invalid signature');
|
||||
}
|
||||
processActivity(req.body);
|
||||
});
|
||||
```
|
||||
|
||||
### 3. SSRF in Media Fetching
|
||||
|
||||
```javascript
|
||||
// Vulnerable
|
||||
async function fetchAvatar(url) {
|
||||
return await fetch(url); // No URL validation
|
||||
}
|
||||
|
||||
// Secure
|
||||
async function fetchAvatar(url) {
|
||||
const parsed = new URL(url);
|
||||
|
||||
// Block internal IPs
|
||||
if (isInternalIP(parsed.hostname)) {
|
||||
throw new Error('Invalid URL');
|
||||
}
|
||||
|
||||
// Only allow http/https
|
||||
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
||||
throw new Error('Invalid protocol');
|
||||
}
|
||||
|
||||
return await fetch(url, { redirect: 'manual' });
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Unescaped Content Rendering
|
||||
|
||||
```javascript
|
||||
// Vulnerable
|
||||
function renderNote(note) {
|
||||
return `<div>${note.content}</div>`; // XSS
|
||||
}
|
||||
|
||||
// Secure
|
||||
function renderNote(note) {
|
||||
const escaped = escapeHtml(note.content);
|
||||
return `<div>${escaped}</div>`;
|
||||
}
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] HTTP signatures verified on all inbox POST requests
|
||||
- [ ] Actor URLs validated (no internal IPs, valid protocols)
|
||||
- [ ] Content sanitized before display (HTML escaping)
|
||||
- [ ] Rate limiting on endpoints
|
||||
- [ ] JSON schema validation
|
||||
- [ ] Authorization checks on Delete/Update activities
|
||||
- [ ] SSRF protection on media fetching
|
||||
- [ ] Proper error handling (no sensitive info in errors)
|
||||
- [ ] CSRF protection
|
||||
- [ ] Content Security Policy headers
|
||||
- [ ] Input size limits
|
||||
- [ ] Secure session management
|
||||
|
||||
## Tools & Resources
|
||||
|
||||
### Testing Tools
|
||||
- This ActivityPub Security PoC
|
||||
- Burp Suite
|
||||
- OWASP ZAP
|
||||
- curl/httpie
|
||||
|
||||
### References
|
||||
- [ActivityPub Specification](https://www.w3.org/TR/activitypub/)
|
||||
- [HTTP Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures)
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [Fediverse Security Best Practices](https://github.com/w3c/activitypub/issues/367)
|
||||
|
||||
## Reporting Format
|
||||
|
||||
When reporting issues, include:
|
||||
|
||||
1. **Title**: Brief description
|
||||
2. **Severity**: Critical/High/Medium/Low
|
||||
3. **Description**: What the vulnerability is
|
||||
4. **Steps to Reproduce**: Detailed reproduction steps
|
||||
5. **Impact**: What an attacker could do
|
||||
6. **Proof of Concept**: Code/payload demonstrating the issue
|
||||
7. **Remediation**: Suggested fix
|
||||
8. **References**: Related CVEs, articles
|
||||
|
||||
### Example Report
|
||||
|
||||
```markdown
|
||||
## XSS in Note Content
|
||||
|
||||
**Severity**: High
|
||||
|
||||
**Description**: User-supplied content in Note objects is rendered without HTML escaping, allowing arbitrary JavaScript execution.
|
||||
|
||||
**Steps to Reproduce**:
|
||||
1. Send Create activity with XSS payload in content field
|
||||
2. View the note in web interface
|
||||
3. Observe JavaScript execution
|
||||
|
||||
**Impact**: Account takeover, data theft, malware distribution
|
||||
|
||||
**Proof of Concept**:
|
||||
```json
|
||||
{
|
||||
"type": "Create",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"content": "<script>alert(document.cookie)</script>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Remediation**: Implement HTML escaping for all user content before rendering.
|
||||
```
|
||||
|
||||
## Legal Considerations
|
||||
|
||||
- Only test systems you own or have explicit permission to test
|
||||
- Comply with computer fraud and abuse laws
|
||||
- Respect bug bounty program terms
|
||||
- Obtain written authorization for penetration testing
|
||||
- Don't disrupt services or access private data
|
||||
|
||||
## Continuous Testing
|
||||
|
||||
Integrate security testing into CI/CD:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security-test.yml
|
||||
name: Security Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run security scan
|
||||
run: |
|
||||
cd activitypub-security-poc
|
||||
npm install
|
||||
npm run mock-server &
|
||||
sleep 5
|
||||
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||
```
|
||||
309
examples/USAGE.md
Archivo normal
309
examples/USAGE.md
Archivo normal
@@ -0,0 +1,309 @@
|
||||
# ActivityPub Security PoC - Usage Examples
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
```bash
|
||||
cd activitypub-security-poc
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Start the Mock Server
|
||||
|
||||
In one terminal:
|
||||
|
||||
```bash
|
||||
node src/cli.js mock-server --port 3000
|
||||
```
|
||||
|
||||
Or using npm script:
|
||||
|
||||
```bash
|
||||
npm run mock-server
|
||||
```
|
||||
|
||||
The mock server will start at `http://localhost:3000` with two test users: `alice` and `bob`.
|
||||
|
||||
### 3. Test the Mock Server
|
||||
|
||||
In another terminal, try fetching an actor profile:
|
||||
|
||||
```bash
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Fetch Actor Profile
|
||||
|
||||
```bash
|
||||
node src/cli.js fetch-actor --target https://mastodon.social/@username
|
||||
```
|
||||
|
||||
### Test Outbox Endpoint
|
||||
|
||||
```bash
|
||||
node src/cli.js test-outbox --target http://localhost:3000/users/alice/outbox
|
||||
```
|
||||
|
||||
### Send Activity to Inbox
|
||||
|
||||
Using a predefined payload:
|
||||
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/create-note.json
|
||||
```
|
||||
|
||||
Using inline content:
|
||||
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--content "Hello from security PoC!" \
|
||||
--actor https://example.com/users/tester
|
||||
```
|
||||
|
||||
### Run Security Scans
|
||||
|
||||
Run all security tests:
|
||||
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--actor http://localhost:3000/users/alice
|
||||
```
|
||||
|
||||
Run specific tests:
|
||||
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--tests xss,ssrf
|
||||
```
|
||||
|
||||
Save results to file:
|
||||
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--output results.json
|
||||
```
|
||||
|
||||
### Craft Custom Activities
|
||||
|
||||
Create a simple note:
|
||||
|
||||
```bash
|
||||
node src/cli.js craft \
|
||||
--type Create \
|
||||
--object Note \
|
||||
--content "Custom activity message" \
|
||||
--actor https://example.com/users/tester \
|
||||
--to https://www.w3.org/ns/activitystreams#Public
|
||||
```
|
||||
|
||||
Save to file:
|
||||
|
||||
```bash
|
||||
node src/cli.js craft \
|
||||
--type Follow \
|
||||
--object https://target.example/users/alice \
|
||||
--actor https://example.com/users/tester \
|
||||
--output examples/my-follow.json
|
||||
```
|
||||
|
||||
## Testing Against Real Instances
|
||||
|
||||
⚠️ **Warning**: Always obtain permission before testing third-party systems!
|
||||
|
||||
### Testing Mastodon
|
||||
|
||||
```bash
|
||||
# Fetch actor
|
||||
node src/cli.js fetch-actor --target https://mastodon.social/@Gargron
|
||||
|
||||
# Fetch outbox
|
||||
node src/cli.js test-outbox --target https://mastodon.social/@Gargron/outbox
|
||||
```
|
||||
|
||||
### Testing Your Own Instance
|
||||
|
||||
If you're running your own Mastodon instance:
|
||||
|
||||
```bash
|
||||
# Security scan on your instance
|
||||
node src/cli.js security-scan \
|
||||
--target https://your-instance.example/users/yourusername/inbox \
|
||||
--tests xss,injection \
|
||||
--output my-instance-scan.json
|
||||
```
|
||||
|
||||
## Security Test Scenarios
|
||||
|
||||
### 1. XSS Testing
|
||||
|
||||
Test for Cross-Site Scripting vulnerabilities:
|
||||
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/xss-payload.json
|
||||
```
|
||||
|
||||
The mock server will detect and log XSS patterns.
|
||||
|
||||
### 2. SSRF Testing
|
||||
|
||||
Test for Server-Side Request Forgery:
|
||||
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload examples/ssrf-payload.json
|
||||
```
|
||||
|
||||
### 3. Full Security Audit
|
||||
|
||||
Run comprehensive tests:
|
||||
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--tests all \
|
||||
--output full-audit-$(date +%Y%m%d).json
|
||||
```
|
||||
|
||||
## Testing Workflow
|
||||
|
||||
### Complete Testing Session
|
||||
|
||||
1. **Start mock server**:
|
||||
```bash
|
||||
npm run mock-server
|
||||
```
|
||||
|
||||
2. **Test basic connectivity**:
|
||||
```bash
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
```
|
||||
|
||||
3. **Send test activity**:
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--content "Testing basic delivery"
|
||||
```
|
||||
|
||||
4. **Run security tests**:
|
||||
```bash
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox
|
||||
```
|
||||
|
||||
5. **Review mock server logs** for detected issues
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Security Tests
|
||||
|
||||
You can create custom payloads by editing the JSON files in `examples/` or creating new ones:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Create",
|
||||
"actor": "https://example.com/users/tester",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"content": "Your custom test content"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then test it:
|
||||
|
||||
```bash
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--payload your-custom-payload.json
|
||||
```
|
||||
|
||||
### Testing Different Activity Types
|
||||
|
||||
```bash
|
||||
# Follow activity
|
||||
node src/cli.js craft --type Follow --object https://target.example/users/alice | \
|
||||
node src/cli.js test-inbox --target http://localhost:3000/users/bob/inbox --payload -
|
||||
|
||||
# Update activity
|
||||
node src/cli.js craft --type Update --content "Updated content"
|
||||
|
||||
# Delete activity
|
||||
node src/cli.js craft --type Delete --object https://example.com/notes/123
|
||||
```
|
||||
|
||||
## Interpreting Results
|
||||
|
||||
### Mock Server Output
|
||||
|
||||
The mock server will display:
|
||||
- 📥 Received activities
|
||||
- ⚠️ Validation warnings
|
||||
- 🚨 Security issues detected
|
||||
|
||||
### Security Scan Output
|
||||
|
||||
- ✅ SAFE - The endpoint properly handled the test
|
||||
- ❌ VULNERABLE - Potential security issue detected
|
||||
|
||||
### Result JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"target": "http://localhost:3000/users/alice/inbox",
|
||||
"timestamp": "2025-11-16T...",
|
||||
"tests": {
|
||||
"xss": [...],
|
||||
"ssrf": [...],
|
||||
"injection": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always test on your own infrastructure first**
|
||||
2. **Get explicit permission before testing external systems**
|
||||
3. **Review logs on both client and server side**
|
||||
4. **Document your findings**
|
||||
5. **Report vulnerabilities responsibly**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Refused
|
||||
|
||||
- Ensure the target server is running
|
||||
- Check firewall rules
|
||||
- Verify the URL is correct
|
||||
|
||||
### 401/403 Errors
|
||||
|
||||
- The endpoint requires authentication
|
||||
- HTTP signatures may be required
|
||||
- Check if the endpoint accepts external activities
|
||||
|
||||
### Timeout Errors
|
||||
|
||||
- Server may be slow or unreachable
|
||||
- Increase timeout with client configuration
|
||||
- Check network connectivity
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Review the source code in `src/` to understand how tests work
|
||||
- Modify `security-tester.js` to add custom tests
|
||||
- Extend `mock-server.js` with more realistic behavior
|
||||
- Integrate with your CI/CD pipeline for automated testing
|
||||
16
examples/create-note.json
Archivo normal
16
examples/create-note.json
Archivo normal
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Create",
|
||||
"id": "https://example.com/activities/test-create-1",
|
||||
"actor": "https://example.com/users/tester",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://example.com/notes/test-note-1",
|
||||
"content": "This is a test note from the ActivityPub security PoC toolkit.",
|
||||
"published": "2025-11-16T00:00:00Z",
|
||||
"attributedTo": "https://example.com/users/tester",
|
||||
"to": ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
},
|
||||
"published": "2025-11-16T00:00:00Z",
|
||||
"to": ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
}
|
||||
8
examples/follow.json
Archivo normal
8
examples/follow.json
Archivo normal
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Follow",
|
||||
"id": "https://example.com/activities/follow-1",
|
||||
"actor": "https://example.com/users/tester",
|
||||
"object": "https://target-instance.example/users/alice",
|
||||
"published": "2025-11-16T00:00:00Z"
|
||||
}
|
||||
19
examples/ssrf-payload.json
Archivo normal
19
examples/ssrf-payload.json
Archivo normal
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Create",
|
||||
"id": "https://example.com/activities/ssrf-test",
|
||||
"actor": "https://example.com/users/tester",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "http://localhost:8080/admin",
|
||||
"url": "http://127.0.0.1:6379",
|
||||
"content": "SSRF test payload",
|
||||
"image": {
|
||||
"type": "Image",
|
||||
"url": "http://169.254.169.254/latest/meta-data/"
|
||||
},
|
||||
"published": "2025-11-16T00:00:00Z",
|
||||
"attributedTo": "https://example.com/users/tester"
|
||||
},
|
||||
"published": "2025-11-16T00:00:00Z"
|
||||
}
|
||||
16
examples/xss-payload.json
Archivo normal
16
examples/xss-payload.json
Archivo normal
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Create",
|
||||
"id": "https://example.com/activities/xss-test",
|
||||
"actor": "https://example.com/users/tester",
|
||||
"object": {
|
||||
"type": "Note",
|
||||
"id": "https://example.com/notes/xss-test",
|
||||
"content": "<script>alert('XSS Test')</script>",
|
||||
"name": "<img src=x onerror=alert('XSS')>",
|
||||
"summary": "javascript:alert('XSS')",
|
||||
"published": "2025-11-16T00:00:00Z",
|
||||
"attributedTo": "https://example.com/users/tester"
|
||||
},
|
||||
"published": "2025-11-16T00:00:00Z"
|
||||
}
|
||||
30
package.json
Archivo normal
30
package.json
Archivo normal
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "activitypub-security-poc",
|
||||
"version": "1.0.0",
|
||||
"description": "Security testing toolkit for ActivityPub protocol",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"ap-security": "./src/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node src/cli.js",
|
||||
"mock-server": "node src/mock-server.js",
|
||||
"test": "node --test"
|
||||
},
|
||||
"keywords": [
|
||||
"activitypub",
|
||||
"security",
|
||||
"fediverse",
|
||||
"testing"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^11.1.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"chalk": "^5.3.0",
|
||||
"jsonld": "^8.3.2",
|
||||
"http-signature": "^1.4.0"
|
||||
}
|
||||
}
|
||||
191
src/activitypub-client.js
Archivo normal
191
src/activitypub-client.js
Archivo normal
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* ActivityPub Client Library
|
||||
* Handles HTTP signatures, JSON-LD, and ActivityPub protocol interactions
|
||||
*/
|
||||
|
||||
import crypto from 'crypto';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
export class ActivityPubClient {
|
||||
constructor(options = {}) {
|
||||
this.userAgent = options.userAgent || 'ActivityPub-Security-PoC/1.0';
|
||||
this.timeout = options.timeout || 10000;
|
||||
this.privateKey = options.privateKey || null;
|
||||
this.publicKey = options.publicKey || null;
|
||||
this.actorId = options.actorId || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an activity to an inbox
|
||||
*/
|
||||
async sendToInbox(inboxUrl, activity, options = {}) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/activity+json',
|
||||
'User-Agent': this.userAgent,
|
||||
...options.headers
|
||||
};
|
||||
|
||||
// Sign the request if we have a private key
|
||||
if (this.privateKey && this.actorId) {
|
||||
const signature = this.signRequest('POST', inboxUrl, activity);
|
||||
headers['Signature'] = signature;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(inboxUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify(activity),
|
||||
timeout: this.timeout
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
body: await this.safeParseResponse(response)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: error.message,
|
||||
type: error.type || 'NetworkError'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from an outbox
|
||||
*/
|
||||
async fetchOutbox(outboxUrl, options = {}) {
|
||||
const headers = {
|
||||
'Accept': 'application/activity+json',
|
||||
'User-Agent': this.userAgent,
|
||||
...options.headers
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(outboxUrl, {
|
||||
method: 'GET',
|
||||
headers,
|
||||
timeout: this.timeout
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
body: await this.safeParseResponse(response)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: error.message,
|
||||
type: error.type || 'NetworkError'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an actor profile
|
||||
*/
|
||||
async fetchActor(actorUrl, options = {}) {
|
||||
const headers = {
|
||||
'Accept': 'application/activity+json',
|
||||
'User-Agent': this.userAgent,
|
||||
...options.headers
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(actorUrl, {
|
||||
method: 'GET',
|
||||
headers,
|
||||
timeout: this.timeout
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
body: await this.safeParseResponse(response)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: error.message,
|
||||
type: error.type || 'NetworkError'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a request using HTTP Signatures
|
||||
*/
|
||||
signRequest(method, url, body) {
|
||||
if (!this.privateKey) {
|
||||
throw new Error('Private key required for signing');
|
||||
}
|
||||
|
||||
const urlObj = new URL(url);
|
||||
const date = new Date().toUTCString();
|
||||
const digest = this.createDigest(JSON.stringify(body));
|
||||
|
||||
const signatureString = `(request-target): ${method.toLowerCase()} ${urlObj.pathname}\nhost: ${urlObj.host}\ndate: ${date}\ndigest: ${digest}`;
|
||||
|
||||
const signer = crypto.createSign('sha256');
|
||||
signer.update(signatureString);
|
||||
signer.end();
|
||||
|
||||
const signature = signer.sign(this.privateKey, 'base64');
|
||||
|
||||
return `keyId="${this.actorId}#main-key",headers="(request-target) host date digest",signature="${signature}"`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SHA-256 digest
|
||||
*/
|
||||
createDigest(body) {
|
||||
const hash = crypto.createHash('sha256').update(body).digest('base64');
|
||||
return `SHA-256=${hash}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely parse response
|
||||
*/
|
||||
async safeParseResponse(response) {
|
||||
const text = await response.text();
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a basic ActivityPub activity
|
||||
*/
|
||||
createActivity(type, object, additionalProps = {}) {
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type,
|
||||
id: `https://example.com/activities/${crypto.randomUUID()}`,
|
||||
actor: this.actorId || 'https://example.com/users/tester',
|
||||
object,
|
||||
published: new Date().toISOString(),
|
||||
...additionalProps
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Note object
|
||||
*/
|
||||
createNote(content, additionalProps = {}) {
|
||||
return {
|
||||
type: 'Note',
|
||||
id: `https://example.com/notes/${crypto.randomUUID()}`,
|
||||
content,
|
||||
published: new Date().toISOString(),
|
||||
attributedTo: this.actorId || 'https://example.com/users/tester',
|
||||
...additionalProps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default ActivityPubClient;
|
||||
242
src/cli.js
Archivo normal
242
src/cli.js
Archivo normal
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* ActivityPub Security PoC CLI
|
||||
* Command-line interface for testing ActivityPub implementations
|
||||
*/
|
||||
|
||||
import { Command } from 'commander';
|
||||
import chalk from 'chalk';
|
||||
import { readFileSync } from 'fs';
|
||||
import { ActivityPubClient } from './activitypub-client.js';
|
||||
import { SecurityTester } from './security-tester.js';
|
||||
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name('ap-security')
|
||||
.description('ActivityPub Security Testing Toolkit')
|
||||
.version('1.0.0');
|
||||
|
||||
/**
|
||||
* Test inbox endpoint
|
||||
*/
|
||||
program
|
||||
.command('test-inbox')
|
||||
.description('Send a test activity to an inbox endpoint')
|
||||
.requiredOption('-t, --target <url>', 'Target inbox URL')
|
||||
.option('-p, --payload <file>', 'JSON file containing the activity payload')
|
||||
.option('-c, --content <text>', 'Text content for a simple Note')
|
||||
.option('--actor <url>', 'Actor ID for the activity')
|
||||
.option('--type <type>', 'Activity type (default: Create)', 'Create')
|
||||
.action(async (options) => {
|
||||
console.log(chalk.blue('\n🔵 Testing inbox endpoint...\n'));
|
||||
|
||||
const client = new ActivityPubClient({
|
||||
actorId: options.actor
|
||||
});
|
||||
|
||||
let activity;
|
||||
|
||||
if (options.payload) {
|
||||
try {
|
||||
const payloadData = readFileSync(options.payload, 'utf8');
|
||||
activity = JSON.parse(payloadData);
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`Error reading payload: ${error.message}`));
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
const content = options.content || 'Test message from ActivityPub Security PoC';
|
||||
const note = client.createNote(content);
|
||||
activity = client.createActivity(options.type, note);
|
||||
}
|
||||
|
||||
console.log(chalk.gray('Activity to send:'));
|
||||
console.log(JSON.stringify(activity, null, 2));
|
||||
console.log();
|
||||
|
||||
const result = await client.sendToInbox(options.target, activity);
|
||||
|
||||
if (result.error) {
|
||||
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||
console.error(chalk.red(`Type: ${result.type}`));
|
||||
} else {
|
||||
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||
console.log(chalk.gray('\nHeaders:'));
|
||||
console.log(result.headers);
|
||||
console.log(chalk.gray('\nBody:'));
|
||||
console.log(JSON.stringify(result.body, null, 2));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test outbox endpoint
|
||||
*/
|
||||
program
|
||||
.command('test-outbox')
|
||||
.description('Fetch activities from an outbox endpoint')
|
||||
.requiredOption('-t, --target <url>', 'Target outbox URL')
|
||||
.option('--page <number>', 'Page number to fetch', '1')
|
||||
.action(async (options) => {
|
||||
console.log(chalk.blue('\n🔵 Fetching outbox...\n'));
|
||||
|
||||
const client = new ActivityPubClient();
|
||||
const result = await client.fetchOutbox(options.target);
|
||||
|
||||
if (result.error) {
|
||||
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||
} else {
|
||||
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||
console.log(chalk.gray('\nOutbox data:'));
|
||||
console.log(JSON.stringify(result.body, null, 2));
|
||||
|
||||
if (result.body && result.body.orderedItems) {
|
||||
console.log(chalk.blue(`\n📊 Total items: ${result.body.orderedItems.length}`));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch actor profile
|
||||
*/
|
||||
program
|
||||
.command('fetch-actor')
|
||||
.description('Fetch an ActivityPub actor profile')
|
||||
.requiredOption('-t, --target <url>', 'Actor URL')
|
||||
.action(async (options) => {
|
||||
console.log(chalk.blue('\n🔵 Fetching actor profile...\n'));
|
||||
|
||||
const client = new ActivityPubClient();
|
||||
const result = await client.fetchActor(options.target);
|
||||
|
||||
if (result.error) {
|
||||
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||
} else {
|
||||
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||
console.log(chalk.gray('\nActor data:'));
|
||||
console.log(JSON.stringify(result.body, null, 2));
|
||||
|
||||
if (result.body) {
|
||||
console.log(chalk.blue('\n📋 Actor Summary:'));
|
||||
console.log(` Name: ${result.body.name || 'N/A'}`);
|
||||
console.log(` Type: ${result.body.type || 'N/A'}`);
|
||||
console.log(` Inbox: ${result.body.inbox || 'N/A'}`);
|
||||
console.log(` Outbox: ${result.body.outbox || 'N/A'}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Run security scan
|
||||
*/
|
||||
program
|
||||
.command('security-scan')
|
||||
.description('Run security tests on an ActivityPub endpoint')
|
||||
.requiredOption('-t, --target <url>', 'Target inbox URL')
|
||||
.option('--tests <types>', 'Comma-separated test types (xss,ssrf,injection,signature,authorization)', 'all')
|
||||
.option('--actor <url>', 'Actor URL (for authorization tests)')
|
||||
.option('-o, --output <file>', 'Save results to JSON file')
|
||||
.action(async (options) => {
|
||||
console.log(chalk.blue('\n🛡️ Starting security scan...\n'));
|
||||
|
||||
const client = new ActivityPubClient();
|
||||
const tester = new SecurityTester(client);
|
||||
|
||||
const testOptions = {
|
||||
actorUrl: options.actor
|
||||
};
|
||||
|
||||
if (options.tests !== 'all') {
|
||||
testOptions.tests = options.tests.split(',').map(t => t.trim());
|
||||
}
|
||||
|
||||
const results = await tester.runAllTests(options.target, testOptions);
|
||||
const summary = tester.generateReport(results);
|
||||
|
||||
if (options.output) {
|
||||
const fs = await import('fs');
|
||||
fs.writeFileSync(options.output, JSON.stringify(results, null, 2));
|
||||
console.log(chalk.green(`\n💾 Results saved to: ${options.output}`));
|
||||
}
|
||||
|
||||
// Exit with error code if vulnerabilities found
|
||||
if (summary.vulnerableTests > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Craft custom activity
|
||||
*/
|
||||
program
|
||||
.command('craft')
|
||||
.description('Craft a custom ActivityPub activity')
|
||||
.option('--type <type>', 'Activity type (Create, Update, Delete, Follow, etc.)', 'Create')
|
||||
.option('--object <objectType>', 'Object type (Note, Article, etc.)', 'Note')
|
||||
.option('--content <text>', 'Content text')
|
||||
.option('--actor <url>', 'Actor ID')
|
||||
.option('--to <url>', 'To field (recipient)')
|
||||
.option('--cc <url>', 'CC field')
|
||||
.option('-o, --output <file>', 'Save to file instead of stdout')
|
||||
.action(async (options) => {
|
||||
const client = new ActivityPubClient({
|
||||
actorId: options.actor || 'https://example.com/users/tester'
|
||||
});
|
||||
|
||||
let object;
|
||||
if (options.object === 'Note') {
|
||||
object = client.createNote(options.content || 'Sample content');
|
||||
} else {
|
||||
object = {
|
||||
type: options.object,
|
||||
id: `https://example.com/objects/${crypto.randomUUID()}`,
|
||||
content: options.content || 'Sample content'
|
||||
};
|
||||
}
|
||||
|
||||
const additionalProps = {};
|
||||
if (options.to) additionalProps.to = options.to;
|
||||
if (options.cc) additionalProps.cc = options.cc;
|
||||
|
||||
const activity = client.createActivity(options.type, object, additionalProps);
|
||||
|
||||
const output = JSON.stringify(activity, null, 2);
|
||||
|
||||
if (options.output) {
|
||||
const fs = await import('fs');
|
||||
fs.writeFileSync(options.output, output);
|
||||
console.log(chalk.green(`✅ Activity saved to: ${options.output}`));
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Start mock server
|
||||
*/
|
||||
program
|
||||
.command('mock-server')
|
||||
.description('Start a mock ActivityPub server for testing')
|
||||
.option('-p, --port <port>', 'Port to listen on', '3000')
|
||||
.option('--host <host>', 'Host to bind to', 'localhost')
|
||||
.action(async (options) => {
|
||||
console.log(chalk.blue(`\n🚀 Starting mock server on ${options.host}:${options.port}...\n`));
|
||||
|
||||
// Dynamic import of mock server
|
||||
const { startMockServer } = await import('./mock-server.js');
|
||||
await startMockServer(options.port, options.host);
|
||||
});
|
||||
|
||||
/**
|
||||
* Interactive mode
|
||||
*/
|
||||
program
|
||||
.command('interactive')
|
||||
.description('Start interactive testing mode')
|
||||
.action(async () => {
|
||||
console.log(chalk.blue('\n🎯 Interactive mode - Coming soon!\n'));
|
||||
console.log('This will provide an interactive prompt for testing ActivityPub endpoints.');
|
||||
});
|
||||
|
||||
program.parse();
|
||||
542
src/mock-server.js
Archivo normal
542
src/mock-server.js
Archivo normal
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* Mock ActivityPub Server
|
||||
* Simulates an ActivityPub server for testing purposes
|
||||
*/
|
||||
|
||||
import http from 'http';
|
||||
import { URL } from 'url';
|
||||
import crypto from 'crypto';
|
||||
import chalk from 'chalk';
|
||||
|
||||
class MockActivityPubServer {
|
||||
constructor(options = {}) {
|
||||
this.host = options.host || 'localhost';
|
||||
this.port = options.port || 3000;
|
||||
this.baseUrl = `http://${this.host}:${this.port}`;
|
||||
this.activities = [];
|
||||
this.users = this.createMockUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create mock user database
|
||||
*/
|
||||
createMockUsers() {
|
||||
return {
|
||||
alice: {
|
||||
'@context': [
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1'
|
||||
],
|
||||
id: `${this.baseUrl}/users/alice`,
|
||||
type: 'Person',
|
||||
preferredUsername: 'alice',
|
||||
name: 'Alice Test',
|
||||
summary: 'Mock ActivityPub user for testing',
|
||||
inbox: `${this.baseUrl}/users/alice/inbox`,
|
||||
outbox: `${this.baseUrl}/users/alice/outbox`,
|
||||
followers: `${this.baseUrl}/users/alice/followers`,
|
||||
following: `${this.baseUrl}/users/alice/following`,
|
||||
publicKey: {
|
||||
id: `${this.baseUrl}/users/alice#main-key`,
|
||||
owner: `${this.baseUrl}/users/alice`,
|
||||
publicKeyPem: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----'
|
||||
},
|
||||
endpoints: {
|
||||
sharedInbox: `${this.baseUrl}/inbox`
|
||||
}
|
||||
},
|
||||
bob: {
|
||||
'@context': [
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1'
|
||||
],
|
||||
id: `${this.baseUrl}/users/bob`,
|
||||
type: 'Person',
|
||||
preferredUsername: 'bob',
|
||||
name: 'Bob Test',
|
||||
summary: 'Another mock ActivityPub user',
|
||||
inbox: `${this.baseUrl}/users/bob/inbox`,
|
||||
outbox: `${this.baseUrl}/users/bob/outbox`,
|
||||
followers: `${this.baseUrl}/users/bob/followers`,
|
||||
following: `${this.baseUrl}/users/bob/following`,
|
||||
publicKey: {
|
||||
id: `${this.baseUrl}/users/bob#main-key`,
|
||||
owner: `${this.baseUrl}/users/bob`,
|
||||
publicKeyPem: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming HTTP requests
|
||||
*/
|
||||
async handleRequest(req, res) {
|
||||
const url = new URL(req.url, this.baseUrl);
|
||||
const path = url.pathname;
|
||||
|
||||
console.log(chalk.gray(`${req.method} ${path}`));
|
||||
|
||||
// Set CORS headers
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept, Signature');
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Route handling
|
||||
if (path === '/.well-known/webfinger') {
|
||||
await this.handleWebFinger(req, res, url);
|
||||
} else if (path.match(/^\/users\/(\w+)$/)) {
|
||||
await this.handleActor(req, res, path);
|
||||
} else if (path.match(/^\/users\/(\w+)\/inbox$/)) {
|
||||
await this.handleInbox(req, res, path);
|
||||
} else if (path.match(/^\/users\/(\w+)\/outbox$/)) {
|
||||
await this.handleOutbox(req, res, path);
|
||||
} else if (path.match(/^\/users\/(\w+)\/followers$/)) {
|
||||
await this.handleFollowers(req, res, path);
|
||||
} else if (path.match(/^\/users\/(\w+)\/following$/)) {
|
||||
await this.handleFollowing(req, res, path);
|
||||
} else if (path === '/inbox') {
|
||||
await this.handleSharedInbox(req, res);
|
||||
} else if (path === '/') {
|
||||
await this.handleRoot(req, res);
|
||||
} else {
|
||||
this.sendNotFound(res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`Error: ${error.message}`));
|
||||
this.sendError(res, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle WebFinger requests
|
||||
*/
|
||||
async handleWebFinger(req, res, url) {
|
||||
const resource = url.searchParams.get('resource');
|
||||
|
||||
if (!resource) {
|
||||
this.sendError(res, new Error('Missing resource parameter'), 400);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract username from resource (e.g., acct:alice@localhost:3000)
|
||||
const match = resource.match(/acct:(\w+)@/);
|
||||
if (!match) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const username = match[1];
|
||||
if (!this.users[username]) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const webfinger = {
|
||||
subject: resource,
|
||||
links: [
|
||||
{
|
||||
rel: 'self',
|
||||
type: 'application/activity+json',
|
||||
href: `${this.baseUrl}/users/${username}`
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.sendJSON(res, webfinger, 200, 'application/jrd+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle actor profile requests
|
||||
*/
|
||||
async handleActor(req, res, path) {
|
||||
const username = path.split('/')[2];
|
||||
const user = this.users[username];
|
||||
|
||||
if (!user) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendJSON(res, user, 200, 'application/activity+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle inbox POST requests
|
||||
*/
|
||||
async handleInbox(req, res, path) {
|
||||
const username = path.split('/')[2];
|
||||
|
||||
if (!this.users[username]) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === 'GET') {
|
||||
// Return inbox collection
|
||||
const inbox = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: `${this.baseUrl}/users/${username}/inbox`,
|
||||
type: 'OrderedCollection',
|
||||
totalItems: this.activities.filter(a => a.to === username).length,
|
||||
orderedItems: this.activities.filter(a => a.to === username)
|
||||
};
|
||||
this.sendJSON(res, inbox, 200, 'application/activity+json');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const body = await this.readBody(req);
|
||||
let activity;
|
||||
|
||||
try {
|
||||
activity = JSON.parse(body);
|
||||
} catch (error) {
|
||||
this.sendError(res, new Error('Invalid JSON'), 400);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(chalk.green(`\n📥 Received activity for ${username}:`));
|
||||
console.log(JSON.stringify(activity, null, 2));
|
||||
|
||||
// Validate activity
|
||||
const validation = this.validateActivity(activity);
|
||||
if (!validation.valid) {
|
||||
console.log(chalk.yellow(`⚠️ Validation warning: ${validation.message}`));
|
||||
}
|
||||
|
||||
// Security checks
|
||||
const securityIssues = this.performSecurityChecks(activity);
|
||||
if (securityIssues.length > 0) {
|
||||
console.log(chalk.red(`\n🚨 Security issues detected:`));
|
||||
securityIssues.forEach(issue => {
|
||||
console.log(chalk.red(` - ${issue}`));
|
||||
});
|
||||
}
|
||||
|
||||
// Store activity
|
||||
this.activities.push({
|
||||
...activity,
|
||||
to: username,
|
||||
receivedAt: new Date().toISOString()
|
||||
});
|
||||
|
||||
res.writeHead(202);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendError(res, new Error('Method not allowed'), 405);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle outbox requests
|
||||
*/
|
||||
async handleOutbox(req, res, path) {
|
||||
const username = path.split('/')[2];
|
||||
|
||||
if (!this.users[username]) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const outbox = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: `${this.baseUrl}/users/${username}/outbox`,
|
||||
type: 'OrderedCollection',
|
||||
totalItems: 2,
|
||||
orderedItems: [
|
||||
{
|
||||
id: `${this.baseUrl}/users/${username}/statuses/1`,
|
||||
type: 'Create',
|
||||
actor: `${this.baseUrl}/users/${username}`,
|
||||
published: new Date().toISOString(),
|
||||
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
object: {
|
||||
id: `${this.baseUrl}/users/${username}/statuses/1`,
|
||||
type: 'Note',
|
||||
content: 'Hello from the mock server!',
|
||||
attributedTo: `${this.baseUrl}/users/${username}`
|
||||
}
|
||||
},
|
||||
{
|
||||
id: `${this.baseUrl}/users/${username}/statuses/2`,
|
||||
type: 'Create',
|
||||
actor: `${this.baseUrl}/users/${username}`,
|
||||
published: new Date().toISOString(),
|
||||
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
object: {
|
||||
id: `${this.baseUrl}/users/${username}/statuses/2`,
|
||||
type: 'Note',
|
||||
content: 'This is a test message for ActivityPub security testing.',
|
||||
attributedTo: `${this.baseUrl}/users/${username}`
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.sendJSON(res, outbox, 200, 'application/activity+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle followers collection
|
||||
*/
|
||||
async handleFollowers(req, res, path) {
|
||||
const username = path.split('/')[2];
|
||||
|
||||
if (!this.users[username]) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const followers = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: `${this.baseUrl}/users/${username}/followers`,
|
||||
type: 'OrderedCollection',
|
||||
totalItems: 0,
|
||||
orderedItems: []
|
||||
};
|
||||
|
||||
this.sendJSON(res, followers, 200, 'application/activity+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle following collection
|
||||
*/
|
||||
async handleFollowing(req, res, path) {
|
||||
const username = path.split('/')[2];
|
||||
|
||||
if (!this.users[username]) {
|
||||
this.sendNotFound(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const following = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: `${this.baseUrl}/users/${username}/following`,
|
||||
type: 'OrderedCollection',
|
||||
totalItems: 0,
|
||||
orderedItems: []
|
||||
};
|
||||
|
||||
this.sendJSON(res, following, 200, 'application/activity+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle shared inbox
|
||||
*/
|
||||
async handleSharedInbox(req, res) {
|
||||
if (req.method === 'POST') {
|
||||
const body = await this.readBody(req);
|
||||
const activity = JSON.parse(body);
|
||||
|
||||
console.log(chalk.green('\n📥 Received activity at shared inbox:'));
|
||||
console.log(JSON.stringify(activity, null, 2));
|
||||
|
||||
this.activities.push(activity);
|
||||
|
||||
res.writeHead(202);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendError(res, new Error('Method not allowed'), 405);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle root path
|
||||
*/
|
||||
async handleRoot(req, res) {
|
||||
const info = {
|
||||
name: 'Mock ActivityPub Server',
|
||||
version: '1.0.0',
|
||||
users: Object.keys(this.users).map(username => ({
|
||||
username,
|
||||
actor: `${this.baseUrl}/users/${username}`,
|
||||
inbox: `${this.baseUrl}/users/${username}/inbox`,
|
||||
outbox: `${this.baseUrl}/users/${username}/outbox`
|
||||
})),
|
||||
endpoints: {
|
||||
sharedInbox: `${this.baseUrl}/inbox`,
|
||||
webfinger: `${this.baseUrl}/.well-known/webfinger`
|
||||
}
|
||||
};
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(info, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate ActivityPub activity
|
||||
*/
|
||||
validateActivity(activity) {
|
||||
if (!activity.type) {
|
||||
return { valid: false, message: 'Missing type field' };
|
||||
}
|
||||
|
||||
if (!activity['@context']) {
|
||||
return { valid: false, message: 'Missing @context' };
|
||||
}
|
||||
|
||||
if (!activity.actor) {
|
||||
return { valid: false, message: 'Missing actor field' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform security checks on activity
|
||||
*/
|
||||
performSecurityChecks(activity) {
|
||||
const issues = [];
|
||||
|
||||
// Check for XSS patterns
|
||||
const xssPatterns = [/<script/i, /javascript:/i, /onerror=/i, /onload=/i];
|
||||
const checkForXSS = (obj) => {
|
||||
for (const value of Object.values(obj)) {
|
||||
if (typeof value === 'string') {
|
||||
for (const pattern of xssPatterns) {
|
||||
if (pattern.test(value)) {
|
||||
issues.push(`Potential XSS detected: ${value.substring(0, 50)}`);
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
checkForXSS(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkForXSS(activity);
|
||||
|
||||
// Check for SSRF attempts
|
||||
const ssrfPatterns = [
|
||||
/localhost/i,
|
||||
/127\.0\.0\.1/,
|
||||
/169\.254\./,
|
||||
/file:\/\//i,
|
||||
/0\.0\.0\.0/
|
||||
];
|
||||
|
||||
const checkForSSRF = (obj) => {
|
||||
for (const value of Object.values(obj)) {
|
||||
if (typeof value === 'string') {
|
||||
for (const pattern of ssrfPatterns) {
|
||||
if (pattern.test(value)) {
|
||||
issues.push(`Potential SSRF detected: ${value}`);
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
checkForSSRF(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkForSSRF(activity);
|
||||
|
||||
// Check for prototype pollution
|
||||
if (activity['__proto__'] || activity.constructor?.prototype) {
|
||||
issues.push('Prototype pollution attempt detected');
|
||||
}
|
||||
|
||||
// Check for SQL injection patterns
|
||||
const sqlPatterns = [/'; DROP/i, /UNION SELECT/i, /' OR '1'='1/i];
|
||||
const checkContent = JSON.stringify(activity);
|
||||
for (const pattern of sqlPatterns) {
|
||||
if (pattern.test(checkContent)) {
|
||||
issues.push('Potential SQL injection pattern detected');
|
||||
}
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read request body
|
||||
*/
|
||||
readBody(req) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let body = '';
|
||||
req.on('data', chunk => {
|
||||
body += chunk.toString();
|
||||
});
|
||||
req.on('end', () => {
|
||||
resolve(body);
|
||||
});
|
||||
req.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JSON response
|
||||
*/
|
||||
sendJSON(res, data, status = 200, contentType = 'application/activity+json') {
|
||||
res.writeHead(status, {
|
||||
'Content-Type': contentType,
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
});
|
||||
res.end(JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error response
|
||||
*/
|
||||
sendError(res, error, status = 500) {
|
||||
res.writeHead(status, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: error.message }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send 404 response
|
||||
*/
|
||||
sendNotFound(res) {
|
||||
this.sendError(res, new Error('Not found'), 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server
|
||||
*/
|
||||
start() {
|
||||
const server = http.createServer((req, res) => this.handleRequest(req, res));
|
||||
|
||||
server.listen(this.port, this.host, () => {
|
||||
console.log(chalk.green(`\n✅ Mock ActivityPub server running!`));
|
||||
console.log(chalk.blue(`\n🌐 Base URL: ${this.baseUrl}`));
|
||||
console.log(chalk.gray('\nAvailable users:'));
|
||||
|
||||
Object.keys(this.users).forEach(username => {
|
||||
console.log(chalk.cyan(` - ${username}`));
|
||||
console.log(chalk.gray(` Actor: ${this.baseUrl}/users/${username}`));
|
||||
console.log(chalk.gray(` Inbox: ${this.baseUrl}/users/${username}/inbox`));
|
||||
console.log(chalk.gray(` Outbox: ${this.baseUrl}/users/${username}/outbox`));
|
||||
});
|
||||
|
||||
console.log(chalk.gray('\nEndpoints:'));
|
||||
console.log(chalk.gray(` - WebFinger: ${this.baseUrl}/.well-known/webfinger?resource=acct:alice@${this.host}`));
|
||||
console.log(chalk.gray(` - Shared Inbox: ${this.baseUrl}/inbox`));
|
||||
console.log(chalk.blue('\n📡 Waiting for requests...\n'));
|
||||
});
|
||||
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the mock server
|
||||
*/
|
||||
export function startMockServer(port = 3000, host = 'localhost') {
|
||||
const server = new MockActivityPubServer({ port, host });
|
||||
return server.start();
|
||||
}
|
||||
|
||||
// If run directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
startMockServer();
|
||||
}
|
||||
|
||||
export default MockActivityPubServer;
|
||||
370
src/security-tester.js
Archivo normal
370
src/security-tester.js
Archivo normal
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* Security Testing Module
|
||||
* Contains various security test scenarios for ActivityPub implementations
|
||||
*/
|
||||
|
||||
import crypto from 'crypto';
|
||||
|
||||
export class SecurityTester {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.results = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Run XSS tests on inbox endpoint
|
||||
*/
|
||||
async testXSS(inboxUrl) {
|
||||
console.log('\n🔍 Testing XSS vulnerabilities...');
|
||||
|
||||
const xssPayloads = [
|
||||
'<script>alert("XSS")</script>',
|
||||
'<img src=x onerror=alert("XSS")>',
|
||||
'javascript:alert("XSS")',
|
||||
'<svg/onload=alert("XSS")>',
|
||||
'"><script>alert(String.fromCharCode(88,83,83))</script>',
|
||||
'<iframe src="javascript:alert(\'XSS\')">',
|
||||
'<body onload=alert("XSS")>'
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const payload of xssPayloads) {
|
||||
const note = this.client.createNote(payload);
|
||||
const activity = this.client.createActivity('Create', note);
|
||||
|
||||
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||
|
||||
results.push({
|
||||
test: 'XSS',
|
||||
payload: payload.substring(0, 50),
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
response: result.statusText
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SSRF vulnerabilities via malicious URLs
|
||||
*/
|
||||
async testSSRF(inboxUrl) {
|
||||
console.log('\n🔍 Testing SSRF vulnerabilities...');
|
||||
|
||||
const ssrfTargets = [
|
||||
'http://localhost:8080',
|
||||
'http://127.0.0.1:6379',
|
||||
'http://169.254.169.254/latest/meta-data/',
|
||||
'http://[::1]:8080',
|
||||
'file:///etc/passwd',
|
||||
'http://0.0.0.0:3000'
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const target of ssrfTargets) {
|
||||
const maliciousObject = {
|
||||
type: 'Note',
|
||||
id: target,
|
||||
url: target,
|
||||
content: 'Test content',
|
||||
image: {
|
||||
type: 'Image',
|
||||
url: target
|
||||
}
|
||||
};
|
||||
|
||||
const activity = this.client.createActivity('Create', maliciousObject);
|
||||
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||
|
||||
results.push({
|
||||
test: 'SSRF',
|
||||
target,
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
response: result.statusText
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test object type confusion/injection
|
||||
*/
|
||||
async testObjectInjection(inboxUrl) {
|
||||
console.log('\n🔍 Testing object injection vulnerabilities...');
|
||||
|
||||
const results = [];
|
||||
|
||||
// Test 1: Malformed type
|
||||
const malformedType = this.client.createActivity('Create', {
|
||||
type: ['Note', 'Delete'],
|
||||
content: 'Type confusion test'
|
||||
});
|
||||
|
||||
let result = await this.client.sendToInbox(inboxUrl, malformedType);
|
||||
results.push({
|
||||
test: 'Type Confusion',
|
||||
payload: 'Multiple types',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202
|
||||
});
|
||||
|
||||
// Test 2: Missing required fields
|
||||
const missingFields = this.client.createActivity('Create', {
|
||||
type: 'Note'
|
||||
// Missing content, attributedTo, etc.
|
||||
});
|
||||
|
||||
result = await this.client.sendToInbox(inboxUrl, missingFields);
|
||||
results.push({
|
||||
test: 'Missing Fields',
|
||||
payload: 'No required fields',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202
|
||||
});
|
||||
|
||||
// Test 3: Prototype pollution attempt
|
||||
const prototypePollution = this.client.createActivity('Create', {
|
||||
type: 'Note',
|
||||
content: 'Test',
|
||||
'__proto__': { isAdmin: true },
|
||||
'constructor': { prototype: { isAdmin: true } }
|
||||
});
|
||||
|
||||
result = await this.client.sendToInbox(inboxUrl, prototypePollution);
|
||||
results.push({
|
||||
test: 'Prototype Pollution',
|
||||
payload: '__proto__ injection',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test signature verification bypass
|
||||
*/
|
||||
async testSignatureBypass(inboxUrl) {
|
||||
console.log('\n🔍 Testing signature bypass vulnerabilities...');
|
||||
|
||||
const results = [];
|
||||
|
||||
// Test 1: No signature
|
||||
const note = this.client.createNote('Unsigned message test');
|
||||
const activity = this.client.createActivity('Create', note);
|
||||
|
||||
let result = await this.client.sendToInbox(inboxUrl, activity);
|
||||
results.push({
|
||||
test: 'No Signature',
|
||||
payload: 'Missing HTTP signature',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
notes: 'Server should reject unsigned requests'
|
||||
});
|
||||
|
||||
// Test 2: Invalid signature
|
||||
result = await this.client.sendToInbox(inboxUrl, activity, {
|
||||
headers: {
|
||||
'Signature': 'keyId="fake",signature="invalidsignature"'
|
||||
}
|
||||
});
|
||||
results.push({
|
||||
test: 'Invalid Signature',
|
||||
payload: 'Malformed signature',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
notes: 'Server should reject invalid signatures'
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test authorization and access control
|
||||
*/
|
||||
async testAuthorization(actorUrl, inboxUrl) {
|
||||
console.log('\n🔍 Testing authorization vulnerabilities...');
|
||||
|
||||
const results = [];
|
||||
|
||||
// Test 1: Impersonation attempt
|
||||
const impersonationNote = this.client.createNote('Impersonation test', {
|
||||
attributedTo: actorUrl // Pretend to be someone else
|
||||
});
|
||||
const impersonationActivity = this.client.createActivity('Create', impersonationNote, {
|
||||
actor: actorUrl // Wrong actor
|
||||
});
|
||||
|
||||
let result = await this.client.sendToInbox(inboxUrl, impersonationActivity);
|
||||
results.push({
|
||||
test: 'Actor Impersonation',
|
||||
payload: 'Mismatched actor',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
notes: 'Server should validate actor matches signature'
|
||||
});
|
||||
|
||||
// Test 2: Unauthorized Delete
|
||||
const deleteActivity = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Delete',
|
||||
actor: 'https://attacker.example/users/evil',
|
||||
object: actorUrl + '/statuses/1' // Try to delete someone else's post
|
||||
};
|
||||
|
||||
result = await this.client.sendToInbox(inboxUrl, deleteActivity);
|
||||
results.push({
|
||||
test: 'Unauthorized Delete',
|
||||
payload: 'Delete others content',
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202,
|
||||
notes: 'Server should verify ownership'
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for injection in various fields
|
||||
*/
|
||||
async testInjection(inboxUrl) {
|
||||
console.log('\n🔍 Testing injection vulnerabilities...');
|
||||
|
||||
const results = [];
|
||||
|
||||
// SQL Injection patterns
|
||||
const sqlPayloads = [
|
||||
"'; DROP TABLE users--",
|
||||
"' OR '1'='1",
|
||||
"admin'--",
|
||||
"' UNION SELECT NULL--"
|
||||
];
|
||||
|
||||
for (const payload of sqlPayloads) {
|
||||
const note = this.client.createNote(payload, {
|
||||
name: payload,
|
||||
summary: payload
|
||||
});
|
||||
const activity = this.client.createActivity('Create', note);
|
||||
|
||||
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||
results.push({
|
||||
test: 'SQL Injection',
|
||||
payload: payload.substring(0, 30),
|
||||
status: result.status,
|
||||
vulnerable: result.error && result.error.includes('SQL')
|
||||
});
|
||||
}
|
||||
|
||||
// Command Injection
|
||||
const cmdPayloads = [
|
||||
'; ls -la',
|
||||
'| whoami',
|
||||
'`id`',
|
||||
'$(uname -a)'
|
||||
];
|
||||
|
||||
for (const payload of cmdPayloads) {
|
||||
const note = this.client.createNote(payload);
|
||||
const activity = this.client.createActivity('Create', note);
|
||||
|
||||
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||
results.push({
|
||||
test: 'Command Injection',
|
||||
payload: payload,
|
||||
status: result.status,
|
||||
vulnerable: result.status === 200 || result.status === 202
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all security tests
|
||||
*/
|
||||
async runAllTests(targetUrl, options = {}) {
|
||||
console.log(`\n🛡️ Starting security tests on: ${targetUrl}\n`);
|
||||
|
||||
const allResults = {
|
||||
target: targetUrl,
|
||||
timestamp: new Date().toISOString(),
|
||||
tests: {}
|
||||
};
|
||||
|
||||
if (!options.tests || options.tests.includes('xss')) {
|
||||
allResults.tests.xss = await this.testXSS(targetUrl);
|
||||
}
|
||||
|
||||
if (!options.tests || options.tests.includes('ssrf')) {
|
||||
allResults.tests.ssrf = await this.testSSRF(targetUrl);
|
||||
}
|
||||
|
||||
if (!options.tests || options.tests.includes('injection')) {
|
||||
allResults.tests.objectInjection = await this.testObjectInjection(targetUrl);
|
||||
allResults.tests.injection = await this.testInjection(targetUrl);
|
||||
}
|
||||
|
||||
if (!options.tests || options.tests.includes('signature')) {
|
||||
allResults.tests.signature = await this.testSignatureBypass(targetUrl);
|
||||
}
|
||||
|
||||
if (!options.tests || options.tests.includes('authorization')) {
|
||||
const actorUrl = options.actorUrl || targetUrl.replace('/inbox', '');
|
||||
allResults.tests.authorization = await this.testAuthorization(actorUrl, targetUrl);
|
||||
}
|
||||
|
||||
return allResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a report from test results
|
||||
*/
|
||||
generateReport(results) {
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('SECURITY TEST REPORT');
|
||||
console.log('='.repeat(60));
|
||||
console.log(`Target: ${results.target}`);
|
||||
console.log(`Timestamp: ${results.timestamp}`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
let totalTests = 0;
|
||||
let vulnerableTests = 0;
|
||||
|
||||
for (const [category, tests] of Object.entries(results.tests)) {
|
||||
console.log(`\n${category.toUpperCase()}:`);
|
||||
console.log('-'.repeat(60));
|
||||
|
||||
for (const test of tests) {
|
||||
totalTests++;
|
||||
const status = test.vulnerable ? '❌ VULNERABLE' : '✅ SAFE';
|
||||
console.log(`${status} - ${test.test}: ${test.payload || test.target || ''}`);
|
||||
|
||||
if (test.notes) {
|
||||
console.log(` Note: ${test.notes}`);
|
||||
}
|
||||
|
||||
if (test.vulnerable) {
|
||||
vulnerableTests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log(`SUMMARY: ${vulnerableTests}/${totalTests} potential vulnerabilities found`);
|
||||
console.log('='.repeat(60) + '\n');
|
||||
|
||||
return {
|
||||
totalTests,
|
||||
vulnerableTests,
|
||||
safeTests: totalTests - vulnerableTests
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default SecurityTester;
|
||||
94
test.sh
Archivo ejecutable
94
test.sh
Archivo ejecutable
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Quick test script for ActivityPub Security PoC
|
||||
# This script demonstrates the main features
|
||||
|
||||
set -e
|
||||
|
||||
echo "================================================"
|
||||
echo "ActivityPub Security PoC - Quick Test"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Check if node_modules exists
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "📦 Installing dependencies..."
|
||||
npm install
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "🚀 Starting mock server in background..."
|
||||
node src/cli.js mock-server --port 3000 > /tmp/mock-server.log 2>&1 &
|
||||
MOCK_PID=$!
|
||||
echo " Mock server PID: $MOCK_PID"
|
||||
|
||||
# Wait for server to start
|
||||
sleep 3
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 1: Fetch Actor Profile"
|
||||
echo "================================================"
|
||||
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 2: Fetch Outbox"
|
||||
echo "================================================"
|
||||
node src/cli.js test-outbox --target http://localhost:3000/users/alice/outbox
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 3: Send Simple Note to Inbox"
|
||||
echo "================================================"
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--content "Hello from security PoC test!" \
|
||||
--actor https://example.com/users/tester
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 4: Send Predefined Payload"
|
||||
echo "================================================"
|
||||
node src/cli.js test-inbox \
|
||||
--target http://localhost:3000/users/bob/inbox \
|
||||
--payload examples/create-note.json
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 5: Craft Custom Activity"
|
||||
echo "================================================"
|
||||
node src/cli.js craft \
|
||||
--type Follow \
|
||||
--actor https://example.com/users/tester \
|
||||
--object http://localhost:3000/users/alice
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Test 6: Security Scan (Limited)"
|
||||
echo "================================================"
|
||||
node src/cli.js security-scan \
|
||||
--target http://localhost:3000/users/alice/inbox \
|
||||
--tests xss,injection \
|
||||
--actor http://localhost:3000/users/alice
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "Tests Complete!"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "📊 Check mock server logs:"
|
||||
echo " tail -f /tmp/mock-server.log"
|
||||
echo ""
|
||||
echo "🛑 Stopping mock server (PID: $MOCK_PID)..."
|
||||
kill $MOCK_PID 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "✅ All tests completed successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " - Review the code in src/"
|
||||
echo " - Read examples/USAGE.md for more examples"
|
||||
echo " - Read docs/SECURITY_TESTING.md for testing methodology"
|
||||
echo " - Start the mock server: npm run mock-server"
|
||||
echo " - Run custom tests with: node src/cli.js --help"
|
||||
Referencia en una nueva incidencia
Block a user