Compare commits
10 Commits
e8c7829bc0
...
b7457a4dc7
| Author | SHA1 | Date | |
|---|---|---|---|
| b7457a4dc7 | |||
| f0674365b3 | |||
| 4e069f39ed | |||
| 91bcb53ab5 | |||
| c562116568 | |||
| d407e95d1c | |||
| 62a4d499ae | |||
| 208227b77e | |||
| dbbde1cc45 | |||
| 31a20b0509 |
@@ -20,5 +20,5 @@ vendor/
|
||||
|
||||
# Docker files (avoid recursion)
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
compose.yml
|
||||
.dockerignore
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/security-linter/php-laravel/main/schema/config.json",
|
||||
"$comment": "Example configuration file for PHP/Laravel Security Linter",
|
||||
|
||||
"severity": "low",
|
||||
|
||||
77
CHANGELOG.md
Normal file
77
CHANGELOG.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.0.1] - 2024-01-31
|
||||
|
||||
### Added
|
||||
|
||||
#### Core Features
|
||||
- Recursive taint analysis for tracking user input through function calls
|
||||
- Multi-language support (Japanese/English)
|
||||
- Syntax highlighting in terminal output
|
||||
- Multiple output formats: text, JSON, HTML, SARIF, Markdown
|
||||
- Docker support for easy deployment
|
||||
- Configuration file support (.security-lint.json)
|
||||
|
||||
#### Vulnerability Detection
|
||||
|
||||
**XSS (Cross-Site Scripting)**
|
||||
- Blade `{!! !!}` raw output detection
|
||||
- JavaScript context XSS
|
||||
- Event handler attribute XSS
|
||||
- URL context XSS (javascript: URLs)
|
||||
- Style injection
|
||||
- Template injection
|
||||
- Escape bypass function detection
|
||||
- Dangerous hardcoded HTML detection
|
||||
|
||||
**SQL Injection**
|
||||
- Laravel Query Builder raw methods
|
||||
- PDO/MySQLi direct queries
|
||||
- String concatenation in queries
|
||||
- Sanitizer bypass detection
|
||||
|
||||
**Command Injection**
|
||||
- Shell execution functions (exec, shell_exec, system, etc.)
|
||||
- Code execution functions (eval, create_function, etc.)
|
||||
- Dynamic file includes
|
||||
- Symfony Process usage
|
||||
|
||||
**Path Traversal**
|
||||
- File operation functions
|
||||
- Laravel Storage operations
|
||||
- File download/upload
|
||||
|
||||
**Authentication Security**
|
||||
- Weak hash algorithms (MD5, SHA1)
|
||||
- Hardcoded credentials detection
|
||||
- Timing-vulnerable comparisons
|
||||
|
||||
**CSRF/Session Security**
|
||||
- Missing CSRF tokens
|
||||
- Insecure session configuration
|
||||
- Session fixation
|
||||
|
||||
**Configuration Security**
|
||||
- Debug output (phpinfo, var_dump, dd)
|
||||
- Insecure unserialize
|
||||
- Sensitive information logging
|
||||
|
||||
**Laravel-Specific Security**
|
||||
- Mass Assignment (missing $fillable/$guarded)
|
||||
- Raw SQL injection (DB::raw, whereRaw without bindings)
|
||||
- CSRF protection (forms without @csrf)
|
||||
- File upload validation (extensions-only without mimes)
|
||||
- Route authentication middleware
|
||||
- Rate limiting for auth routes
|
||||
|
||||
### Security
|
||||
- Safe pattern recognition for Laravel helpers (route(), url(), action())
|
||||
- Value-based credential detection to reduce false positives
|
||||
- Escape function recognition (htmlspecialchars, e(), etc.)
|
||||
|
||||
[0.0.1]: https://opensource.rogarithm.net/rogarithm/php-security-linter/releases/tag/v0.0.1
|
||||
204
CONTRIBUTING.md
Normal file
204
CONTRIBUTING.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Contributing to PHP/Laravel Security Linter
|
||||
|
||||
Thank you for your interest in contributing to this project! This document provides guidelines and instructions for contributing.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please be respectful and constructive in all interactions. We welcome contributors of all experience levels.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
1. Check if the issue already exists in [Gitea Issues](https://opensource.rogarithm.net/rogarithm/php-security-linter/issues)
|
||||
2. If not, create a new issue with:
|
||||
- Clear description of the problem
|
||||
- Steps to reproduce
|
||||
- Expected vs actual behavior
|
||||
- PHP/Laravel versions
|
||||
- Sample code that triggers the issue
|
||||
|
||||
### Reporting False Positives/Negatives
|
||||
|
||||
Security linters can produce false positives (safe code flagged as vulnerable) or false negatives (vulnerable code not detected). Please report these with:
|
||||
- The code snippet being analyzed
|
||||
- Why you believe it's a false positive/negative
|
||||
- Any relevant context
|
||||
|
||||
### Suggesting Features
|
||||
|
||||
1. Check existing issues and discussions
|
||||
2. Create a new issue describing:
|
||||
- The vulnerability type you want to detect
|
||||
- Example vulnerable and safe code patterns
|
||||
- References to security documentation (CWE, OWASP, etc.)
|
||||
|
||||
### Pull Requests
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feature/your-feature-name`
|
||||
3. Make your changes
|
||||
4. Test your changes
|
||||
5. Commit with clear messages
|
||||
6. Push and create a Pull Request
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Requirements
|
||||
|
||||
- PHP 8.1+
|
||||
- Composer
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git
|
||||
cd php-laravel
|
||||
composer install
|
||||
```
|
||||
|
||||
### Running the Linter
|
||||
|
||||
```bash
|
||||
# Analyze a file
|
||||
php bin/security-lint path/to/file.php
|
||||
|
||||
# Analyze a directory
|
||||
php bin/security-lint path/to/directory/
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
├── bin/
|
||||
│ └── security-lint # CLI entry point
|
||||
├── src/
|
||||
│ ├── SecurityLinter.php # Main linter class
|
||||
│ ├── Rules/ # Detection rules
|
||||
│ │ ├── XssRule.php
|
||||
│ │ ├── SqlInjectionRule.php
|
||||
│ │ ├── CommandInjectionRule.php
|
||||
│ │ ├── PathTraversalRule.php
|
||||
│ │ ├── AuthenticationRule.php
|
||||
│ │ ├── CsrfRule.php
|
||||
│ │ ├── InsecureConfigRule.php
|
||||
│ │ └── LaravelSecurityRule.php
|
||||
│ ├── Analysis/ # Analysis utilities
|
||||
│ │ ├── TaintAnalyzer.php
|
||||
│ │ └── FunctionAnalyzer.php
|
||||
│ ├── Report/ # Report generation
|
||||
│ │ ├── Vulnerability.php
|
||||
│ │ └── ReportGenerator.php
|
||||
│ └── I18n/ # Internationalization
|
||||
│ └── Messages.php
|
||||
├── docs/ # Documentation
|
||||
│ ├── DETECTION_RULES.md
|
||||
│ └── QUICK_REFERENCE.md
|
||||
└── test-samples/ # Test samples
|
||||
```
|
||||
|
||||
## Adding New Detection Rules
|
||||
|
||||
### 1. Create a New Rule Class
|
||||
|
||||
Create a new file in `src/Rules/`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace SecurityLinter\Rules;
|
||||
|
||||
use PhpParser\Node;
|
||||
use SecurityLinter\Report\Vulnerability;
|
||||
|
||||
class YourNewRule extends AbstractRule
|
||||
{
|
||||
protected string $name = 'your_rule';
|
||||
|
||||
public function analyze(Node $node, string $file, array $context = []): array
|
||||
{
|
||||
$vulnerabilities = [];
|
||||
|
||||
// Your detection logic here
|
||||
|
||||
return $vulnerabilities;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the Rule
|
||||
|
||||
Add your rule to `SecurityLinter.php`:
|
||||
|
||||
```php
|
||||
private function registerDefaultRules(): void
|
||||
{
|
||||
$this->rules = [
|
||||
// ... existing rules
|
||||
new YourNewRule(),
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add Messages
|
||||
|
||||
Add messages in `src/I18n/Messages.php` for both Japanese and English:
|
||||
|
||||
```php
|
||||
// Japanese
|
||||
'your_rule.name' => 'ルール名',
|
||||
'your_rule.vulnerability_message' => '脆弱性の説明...',
|
||||
|
||||
// English
|
||||
'your_rule.name' => 'Rule Name',
|
||||
'your_rule.vulnerability_message' => 'Vulnerability description...',
|
||||
```
|
||||
|
||||
### 4. Update Documentation
|
||||
|
||||
- Add detection patterns to `docs/DETECTION_RULES.md`
|
||||
- Update README.md if needed
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing
|
||||
|
||||
Create test files in `test-samples/` to verify detection:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// test-samples/your-test.php
|
||||
|
||||
// VULNERABLE: Should be detected
|
||||
vulnerable_pattern();
|
||||
|
||||
// SAFE: Should not be detected
|
||||
safe_pattern();
|
||||
```
|
||||
|
||||
Run the linter against your test files:
|
||||
|
||||
```bash
|
||||
php bin/security-lint test-samples/your-test.php -c
|
||||
```
|
||||
|
||||
## Commit Guidelines
|
||||
|
||||
- Use clear, descriptive commit messages
|
||||
- Reference issue numbers when applicable
|
||||
- Keep commits focused on single changes
|
||||
|
||||
Example:
|
||||
```
|
||||
Add detection for insecure deserialization
|
||||
|
||||
- Detect unserialize() with allowed_classes => true
|
||||
- Add messages in Japanese and English
|
||||
- Update DETECTION_RULES.md
|
||||
|
||||
Fixes #123
|
||||
```
|
||||
|
||||
## Questions?
|
||||
|
||||
Feel free to open an issue for questions or discussions.
|
||||
@@ -2,7 +2,7 @@ FROM php:8.3-cli-alpine
|
||||
|
||||
LABEL maintainer="Security Linter Team"
|
||||
LABEL description="PHP/Laravel Security Linter - Static security analysis tool"
|
||||
LABEL version="1.0.0"
|
||||
LABEL version="0.0.1"
|
||||
|
||||
# Build arguments
|
||||
ARG PHP_MEMORY_LIMIT=1024M
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Security Linter Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
136
README.md
136
README.md
@@ -24,33 +24,62 @@ Detects vulnerabilities through recursive taint analysis by tracking data flow a
|
||||
|
||||
#### Method 1: Docker (Recommended)
|
||||
|
||||
No PHP or Composer environment required.
|
||||
No PHP or Composer environment required. Just Docker.
|
||||
|
||||
**Step 1: Clone and build**
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/your-org/php-laravel-security-linter.git
|
||||
cd php-laravel-security-linter
|
||||
|
||||
# Install (builds Docker image and installs command)
|
||||
./install.sh
|
||||
git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git
|
||||
cd php-security-linter
|
||||
docker build -t php-security-linter:latest .
|
||||
```
|
||||
|
||||
After installation, use the `php-security-lint` command:
|
||||
**Note:** For large projects, you may need to increase the PHP memory limit:
|
||||
|
||||
```bash
|
||||
# Build with 2GB memory limit (default: 1024M)
|
||||
docker build --build-arg PHP_MEMORY_LIMIT=2048M -t php-security-linter:latest .
|
||||
```
|
||||
|
||||
**Step 2: Run**
|
||||
|
||||
```bash
|
||||
# Scan your project directory
|
||||
docker run --rm -v /path/to/your/project:/target:ro php-security-linter:latest /target
|
||||
|
||||
# Scan current directory
|
||||
docker run --rm -v $(pwd):/target:ro php-security-linter:latest /target
|
||||
|
||||
# With options (high severity only, JSON output)
|
||||
docker run --rm -v $(pwd):/target php-security-linter:latest /target -s high -f json -o /target/report.json
|
||||
```
|
||||
|
||||
**Optional: Install wrapper command**
|
||||
|
||||
For convenience, you can install a wrapper script:
|
||||
|
||||
```bash
|
||||
./install.sh
|
||||
|
||||
# Or with custom memory limit
|
||||
PHP_MEMORY_LIMIT=2048M ./install.sh
|
||||
```
|
||||
|
||||
After installation, use the `php-security-lint` command anywhere:
|
||||
|
||||
```bash
|
||||
# Run in your project directory
|
||||
cd /path/to/your/laravel-project
|
||||
php-security-lint .
|
||||
php-security-lint app/ -s high
|
||||
```
|
||||
|
||||
#### Method 2: Direct Execution
|
||||
#### Method 2: Direct Execution (PHP Required)
|
||||
|
||||
Requires PHP 8.1+ and Composer.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/php-laravel-security-linter.git
|
||||
cd php-laravel-security-linter
|
||||
git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git
|
||||
cd php-security-linter
|
||||
composer install
|
||||
php bin/security-lint /path/to/target
|
||||
```
|
||||
@@ -194,11 +223,20 @@ Place `.security-lint.json` in your project root to persist settings:
|
||||
- Insecure unserialize
|
||||
- Sensitive information logging
|
||||
|
||||
#### Laravel-Specific Security
|
||||
|
||||
- Mass Assignment (missing $fillable/$guarded, using $request->all())
|
||||
- Raw SQL injection (DB::raw, whereRaw without bindings)
|
||||
- CSRF protection (forms without @csrf)
|
||||
- File upload validation (extensions-only without mimes)
|
||||
- Route authentication (sensitive routes without auth middleware)
|
||||
- Rate limiting (auth routes without throttle middleware)
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ PHP/Laravel Security Linter v1.0.0 ║
|
||||
║ PHP/Laravel Security Linter v0.0.1 ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
Analyzing: app/
|
||||
|
||||
@@ -258,7 +296,7 @@ jobs:
|
||||
- name: Run Security Linter
|
||||
run: |
|
||||
docker run --rm -v ${{ github.workspace }}:/target \
|
||||
ghcr.io/your-org/php-security-linter:latest \
|
||||
php-security-linter:latest \
|
||||
/target -s high -f sarif -o /target/security.sarif
|
||||
|
||||
- name: Upload SARIF
|
||||
@@ -271,7 +309,7 @@ jobs:
|
||||
|
||||
```yaml
|
||||
security-lint:
|
||||
image: ghcr.io/your-org/php-security-linter:latest
|
||||
image: php-security-linter:latest
|
||||
script:
|
||||
- security-lint . -s medium -f json -o security-report.json
|
||||
artifacts:
|
||||
@@ -323,33 +361,62 @@ PHP および Laravel アプリケーション向けの静的セキュリティ
|
||||
|
||||
#### 方法1: Docker(推奨)
|
||||
|
||||
PHPやComposerの環境構築なしで使用できます。
|
||||
PHPやComposerの環境構築は不要です。Dockerのみで動作します。
|
||||
|
||||
**ステップ1: クローンとビルド**
|
||||
|
||||
```bash
|
||||
# リポジトリをクローン
|
||||
git clone https://github.com/your-org/php-laravel-security-linter.git
|
||||
cd php-laravel-security-linter
|
||||
|
||||
# インストール (Dockerイメージのビルドとコマンドのインストール)
|
||||
./install.sh
|
||||
git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git
|
||||
cd php-security-linter
|
||||
docker build -t php-security-linter:latest .
|
||||
```
|
||||
|
||||
インストール後は `php-security-lint` コマンドで使用できます:
|
||||
**注意:** 大規模なプロジェクトでは、PHPのメモリ制限を増やす必要がある場合があります:
|
||||
|
||||
```bash
|
||||
# 2GBのメモリ制限でビルド(デフォルト: 1024M)
|
||||
docker build --build-arg PHP_MEMORY_LIMIT=2048M -t php-security-linter:latest .
|
||||
```
|
||||
|
||||
**ステップ2: 実行**
|
||||
|
||||
```bash
|
||||
# プロジェクトディレクトリをスキャン
|
||||
docker run --rm -v /path/to/your/project:/target:ro php-security-linter:latest /target
|
||||
|
||||
# カレントディレクトリをスキャン
|
||||
docker run --rm -v $(pwd):/target:ro php-security-linter:latest /target
|
||||
|
||||
# オプション付き(高重大度のみ、JSON出力)
|
||||
docker run --rm -v $(pwd):/target php-security-linter:latest /target -s high -f json -o /target/report.json
|
||||
```
|
||||
|
||||
**オプション: ラッパーコマンドのインストール**
|
||||
|
||||
便利なラッパースクリプトをインストールできます:
|
||||
|
||||
```bash
|
||||
./install.sh
|
||||
|
||||
# メモリ制限を指定する場合
|
||||
PHP_MEMORY_LIMIT=2048M ./install.sh
|
||||
```
|
||||
|
||||
インストール後は `php-security-lint` コマンドでどこからでも使用できます:
|
||||
|
||||
```bash
|
||||
# プロジェクトディレクトリで実行
|
||||
cd /path/to/your/laravel-project
|
||||
php-security-lint .
|
||||
php-security-lint app/ -s high
|
||||
```
|
||||
|
||||
#### 方法2: 直接実行
|
||||
#### 方法2: 直接実行(PHP必須)
|
||||
|
||||
PHP 8.1以上とComposerが必要です。
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/php-laravel-security-linter.git
|
||||
cd php-laravel-security-linter
|
||||
git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git
|
||||
cd php-security-linter
|
||||
composer install
|
||||
php bin/security-lint /path/to/target
|
||||
```
|
||||
@@ -493,11 +560,20 @@ php bin/security-lint app/ -l en
|
||||
- 安全でない unserialize
|
||||
- 機密情報のログ出力
|
||||
|
||||
#### Laravel特有のセキュリティ
|
||||
|
||||
- Mass Assignment ($fillable/$guarded の欠落、$request->all() の使用)
|
||||
- Raw SQL インジェクション (DB::raw、バインディングなしの whereRaw)
|
||||
- CSRF 保護 (@csrf のないフォーム)
|
||||
- ファイルアップロード検証 (mimes なしの extensions のみ)
|
||||
- ルート認証 (auth ミドルウェアのないセンシティブなルート)
|
||||
- レート制限 (throttle ミドルウェアのない認証ルート)
|
||||
|
||||
### 出力例
|
||||
|
||||
```
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ PHP/Laravel セキュリティリンター v1.0.0 ║
|
||||
║ PHP/Laravel セキュリティリンター v0.0.1 ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
解析中: app/
|
||||
|
||||
@@ -557,7 +633,7 @@ jobs:
|
||||
- name: Run Security Linter
|
||||
run: |
|
||||
docker run --rm -v ${{ github.workspace }}:/target \
|
||||
ghcr.io/your-org/php-security-linter:latest \
|
||||
php-security-linter:latest \
|
||||
/target -s high -f sarif -o /target/security.sarif
|
||||
|
||||
- name: Upload SARIF
|
||||
@@ -570,7 +646,7 @@ jobs:
|
||||
|
||||
```yaml
|
||||
security-lint:
|
||||
image: ghcr.io/your-org/php-security-linter:latest
|
||||
image: php-security-linter:latest
|
||||
script:
|
||||
- security-lint . -s medium -f json -o security-report.json
|
||||
artifacts:
|
||||
|
||||
@@ -35,7 +35,7 @@ use SecurityLinter\I18n\Messages;
|
||||
*/
|
||||
class SecurityLintCLI
|
||||
{
|
||||
private const VERSION = '1.0.0';
|
||||
private const VERSION = '0.0.1';
|
||||
|
||||
/** @var array Default directories/patterns to exclude */
|
||||
private const DEFAULT_EXCLUDES = [
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
security-lint:
|
||||
build:
|
||||
@@ -10,4 +8,4 @@ services:
|
||||
# Mount the target directory as read-only
|
||||
- ${TARGET_PATH:-.}:/target:ro
|
||||
# Default command can be overridden
|
||||
# Example: docker-compose run --rm security-lint /target/app -s high
|
||||
# Example: docker compose run --rm security-lint /target/app -s high
|
||||
@@ -1,8 +1,31 @@
|
||||
{
|
||||
"name": "security-linter/php-laravel",
|
||||
"description": "Security linter for PHP and Laravel applications",
|
||||
"description": "A static security analysis tool for PHP and Laravel applications with recursive taint analysis",
|
||||
"version": "0.0.1",
|
||||
"type": "project",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"security",
|
||||
"linter",
|
||||
"static-analysis",
|
||||
"php",
|
||||
"laravel",
|
||||
"xss",
|
||||
"sql-injection",
|
||||
"vulnerability",
|
||||
"sast"
|
||||
],
|
||||
"homepage": "https://opensource.rogarithm.net/rogarithm/php-security-linter",
|
||||
"support": {
|
||||
"issues": "https://opensource.rogarithm.net/rogarithm/php-security-linter/issues",
|
||||
"source": "https://opensource.rogarithm.net/rogarithm/php-security-linter"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Security Linter Contributors",
|
||||
"homepage": "https://opensource.rogarithm.net/rogarithm/php-security-linter/contributors"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SecurityLinter\\": "src/"
|
||||
@@ -12,5 +35,13 @@
|
||||
"php": ">=8.1",
|
||||
"nikic/php-parser": "^5.0"
|
||||
},
|
||||
"bin": ["bin/security-lint"]
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/security-lint"
|
||||
],
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
5. [認証セキュリティ](#5-認証セキュリティ)
|
||||
6. [CSRF/セッションセキュリティ](#6-csrfセッションセキュリティ)
|
||||
7. [設定セキュリティ](#7-設定セキュリティ)
|
||||
8. [Laravel特有のセキュリティ](#8-laravel特有のセキュリティ)
|
||||
|
||||
---
|
||||
|
||||
@@ -751,6 +752,241 @@ unserialize($data, ['allowed_classes' => [AllowedClass::class]]);
|
||||
|
||||
---
|
||||
|
||||
## 8. Laravel特有のセキュリティ
|
||||
|
||||
Laravel フレームワーク固有の脆弱性パターンを検出します。
|
||||
|
||||
### 8.1 Mass Assignment(一括代入)
|
||||
|
||||
Eloquent モデルで `$fillable` または `$guarded` プロパティが定義されていない場合を検出します。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| Model without `$fillable` or `$guarded` | HIGH |
|
||||
| `Model::create($request->all())` | HIGH |
|
||||
| `$model->fill($request->all())` | HIGH |
|
||||
| `$model->update($request->all())` | HIGH |
|
||||
|
||||
**脆弱なコード:**
|
||||
```php
|
||||
// 危険: $fillable/$guarded がない
|
||||
class User extends Model
|
||||
{
|
||||
// Mass Assignment 脆弱性
|
||||
}
|
||||
|
||||
// 危険: $request->all() を直接使用
|
||||
User::create($request->all());
|
||||
$user->update($request->all());
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```php
|
||||
// $fillable を定義
|
||||
class User extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'email'];
|
||||
}
|
||||
|
||||
// または $guarded を定義
|
||||
class User extends Model
|
||||
{
|
||||
protected $guarded = ['id', 'is_admin'];
|
||||
}
|
||||
|
||||
// 特定のフィールドのみ使用
|
||||
User::create($request->only(['name', 'email']));
|
||||
$user->update($request->validated());
|
||||
```
|
||||
|
||||
### 8.2 Raw SQL インジェクション
|
||||
|
||||
Laravel のクエリビルダーで生SQLを使用し、パラメータバインディングがない場合を検出します。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| `DB::raw($variable)` | HIGH |
|
||||
| `whereRaw($sql)` (バインディングなし) | HIGH |
|
||||
| `selectRaw($sql)` (バインディングなし) | HIGH |
|
||||
| `orderByRaw($sql)` (バインディングなし) | HIGH |
|
||||
| `havingRaw($sql)` (バインディングなし) | HIGH |
|
||||
| `groupByRaw($sql)` (バインディングなし) | HIGH |
|
||||
|
||||
**脆弱なコード:**
|
||||
```php
|
||||
// 危険: 変数を含む DB::raw
|
||||
$column = $request->input('column');
|
||||
DB::table('users')->select(DB::raw($column))->get();
|
||||
|
||||
// 危険: バインディングなしの whereRaw
|
||||
$name = $request->input('name');
|
||||
User::whereRaw("name = '$name'")->get();
|
||||
|
||||
// 危険: バインディングなしの orderByRaw
|
||||
$order = $request->input('order');
|
||||
User::orderByRaw($order)->get();
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```php
|
||||
// パラメータバインディングを使用
|
||||
User::whereRaw('name = ?', [$name])->get();
|
||||
User::orderByRaw('FIELD(status, ?, ?, ?)', ['active', 'pending', 'inactive'])->get();
|
||||
|
||||
// クエリビルダーを使用(推奨)
|
||||
User::where('name', $name)->get();
|
||||
User::orderBy($allowedColumns[$request->input('column')])->get();
|
||||
```
|
||||
|
||||
### 8.3 CSRF 保護
|
||||
|
||||
POST/PUT/PATCH/DELETE メソッドのフォームに CSRF トークンがない場合を検出します。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| `<form method="POST">` without `@csrf` | HIGH |
|
||||
| `<form method="post">` without `csrf_field()` | HIGH |
|
||||
| `<form method="PUT">` without CSRF | HIGH |
|
||||
| `<form method="DELETE">` without CSRF | HIGH |
|
||||
|
||||
**脆弱なコード:**
|
||||
```blade
|
||||
{{-- 危険: @csrf がない --}}
|
||||
<form method="POST" action="/submit">
|
||||
<input type="text" name="data">
|
||||
<button type="submit">送信</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```blade
|
||||
{{-- @csrf ディレクティブを使用 --}}
|
||||
<form method="POST" action="/submit">
|
||||
@csrf
|
||||
<input type="text" name="data">
|
||||
<button type="submit">送信</button>
|
||||
</form>
|
||||
|
||||
{{-- または csrf_field() ヘルパー --}}
|
||||
<form method="POST" action="/submit">
|
||||
{{ csrf_field() }}
|
||||
<input type="text" name="data">
|
||||
<button type="submit">送信</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
### 8.4 ファイルアップロード検証
|
||||
|
||||
ファイルアップロードで `extensions` ルールのみを使用し、`mimes` または `mimetypes` ルールがない場合を検出します。拡張子のみのチェックは簡単にバイパスできます。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| `'file' => 'extensions:jpg,png'` (mimes なし) | MEDIUM |
|
||||
| `'file' => ['extensions:jpg', 'file']` (mimes なし) | MEDIUM |
|
||||
|
||||
**脆弱なコード:**
|
||||
```php
|
||||
// 危険: 拡張子のみで検証
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'avatar' => ['required', 'file', 'extensions:jpg,png'],
|
||||
'document' => 'file|extensions:pdf,doc',
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```php
|
||||
// mimes または mimetypes を併用
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
// mimes を使用(推奨)
|
||||
'avatar' => ['required', 'file', 'mimes:jpeg,png'],
|
||||
|
||||
// extensions と mimes を両方使用
|
||||
'document' => ['file', 'extensions:pdf,doc', 'mimes:pdf,msword'],
|
||||
|
||||
// mimetypes を使用
|
||||
'video' => ['file', 'mimetypes:video/mp4,video/mpeg'],
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### 8.5 ルート認証ミドルウェア
|
||||
|
||||
センシティブなルートに `auth` ミドルウェアがない場合を検出します。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| `Route::*('/admin/*')` without auth | LOW |
|
||||
| `Route::*('/dashboard/*')` without auth | LOW |
|
||||
| `Route::*('/user/*')` without auth | LOW |
|
||||
| `Route::*('/account/*')` without auth | LOW |
|
||||
| `Route::*('/settings/*')` without auth | LOW |
|
||||
| `Route::*('/profile/*')` without auth | LOW |
|
||||
|
||||
**検出対象のセンシティブなルートパターン:**
|
||||
- `/admin/`, `/dashboard/`, `/user/`, `/users/`
|
||||
- `/account/`, `/settings/`, `/profile/`
|
||||
- `/manage/`, `/management/`, `/billing/`
|
||||
|
||||
**脆弱なコード:**
|
||||
```php
|
||||
// 危険: 認証なしで管理画面にアクセス可能
|
||||
Route::get('/admin/dashboard', [AdminController::class, 'index']);
|
||||
Route::get('/users/manage', [UserController::class, 'manage']);
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```php
|
||||
// ルートにミドルウェアを追加
|
||||
Route::get('/admin/dashboard', [AdminController::class, 'index'])
|
||||
->middleware('auth');
|
||||
|
||||
// グループでミドルウェアを適用(推奨)
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::get('/admin/dashboard', [AdminController::class, 'index']);
|
||||
Route::get('/users/manage', [UserController::class, 'manage']);
|
||||
});
|
||||
```
|
||||
|
||||
### 8.6 レート制限
|
||||
|
||||
認証関連のルートに `throttle` ミドルウェアがない場合を検出します。ブルートフォース攻撃を防ぐために重要です。
|
||||
|
||||
| パターン | 重大度 |
|
||||
|---------|--------|
|
||||
| `Route::post('/login')` without throttle | LOW |
|
||||
| `Route::post('/register')` without throttle | LOW |
|
||||
| `Route::post('/password/reset')` without throttle | LOW |
|
||||
| `Route::post('/password/email')` without throttle | LOW |
|
||||
| `Route::post('/forgot-password')` without throttle | LOW |
|
||||
| `Route::post('/2fa/*')` without throttle | LOW |
|
||||
|
||||
**脆弱なコード:**
|
||||
```php
|
||||
// 危険: レート制限なしでブルートフォース可能
|
||||
Route::post('/login', [AuthController::class, 'login']);
|
||||
Route::post('/password/reset', [PasswordController::class, 'reset']);
|
||||
```
|
||||
|
||||
**安全なコード:**
|
||||
```php
|
||||
// throttle ミドルウェアを追加
|
||||
Route::post('/login', [AuthController::class, 'login'])
|
||||
->middleware('throttle:5,1'); // 1分間に5回まで
|
||||
|
||||
// グループでレート制限を適用
|
||||
Route::middleware(['throttle:60,1'])->group(function () {
|
||||
Route::post('/login', [AuthController::class, 'login']);
|
||||
Route::post('/password/reset', [PasswordController::class, 'reset']);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 再帰的なテイント解析
|
||||
|
||||
リンターは、関数呼び出しを通じてユーザー入力(テイントデータ)がどのように伝播するかを追跡します。
|
||||
@@ -856,6 +1092,6 @@ php bin/security-lint app/ -l en
|
||||
|
||||
## バージョン
|
||||
|
||||
- ドキュメント作成日: 2024
|
||||
- 対応 PHP バージョン: 8.0+
|
||||
- バージョン: 0.0.1
|
||||
- 対応 PHP バージョン: 8.1+
|
||||
- 対応 Laravel バージョン: 9.x, 10.x, 11.x
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
# php-security-lint -s high -f json .
|
||||
#
|
||||
# Installation:
|
||||
# curl -o /usr/local/bin/php-security-lint https://raw.githubusercontent.com/your-org/php-laravel-security-linter/main/php-security-lint
|
||||
# chmod +x /usr/local/bin/php-security-lint
|
||||
# Copy this script to /usr/local/bin/ after building the Docker image:
|
||||
# sudo cp php-security-lint /usr/local/bin/
|
||||
# sudo chmod +x /usr/local/bin/php-security-lint
|
||||
#
|
||||
|
||||
set -e
|
||||
@@ -106,11 +107,10 @@ check_image() {
|
||||
else
|
||||
echo -e "${RED}Error: Docker image '$DOCKER_IMAGE' not found.${NC}" >&2
|
||||
echo "" >&2
|
||||
echo "To build the image, run from the security-linter directory:" >&2
|
||||
echo "To build the image, clone the repository and run:" >&2
|
||||
echo " git clone https://opensource.rogarithm.net/rogarithm/php-security-linter.git" >&2
|
||||
echo " cd php-security-linter" >&2
|
||||
echo " docker build -t php-security-linter:latest ." >&2
|
||||
echo "" >&2
|
||||
echo "Or pull from registry (if published):" >&2
|
||||
echo " docker pull your-org/php-security-linter:latest" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -293,6 +293,25 @@ class Messages
|
||||
'config.env_no_default' => '変数が存在しない場合に問題を引き起こす可能性があるデフォルト値なしの env() が呼び出されています。',
|
||||
'config.env_no_default.rec' => 'デフォルト値を指定してください: env(\'KEY\', \'default\')',
|
||||
|
||||
// Laravel-specific messages
|
||||
'laravel.name' => 'Laravelセキュリティ',
|
||||
'laravel.mass_assignment' => 'Eloquentモデル \':class\' に $fillable または $guarded プロパティが定義されていません。Mass Assignment攻撃に対して脆弱です。',
|
||||
'laravel.mass_assignment.rec' => 'モデルに protected $fillable = [...] または protected $guarded = [...] を定義してください。',
|
||||
'laravel.mass_assignment_all' => ':method() で $request->all() を使用しています。Mass Assignment攻撃のリスクがあります。',
|
||||
'laravel.mass_assignment_all.rec' => '$request->only([\'field1\', \'field2\']) または $request->validated() を使用してください。',
|
||||
'laravel.raw_sql' => ':method() でパラメータバインディングなしの生SQLを使用しています。SQLインジェクションのリスクがあります。',
|
||||
'laravel.raw_sql.rec' => 'バインディングを使用してください: ->:method(\'column = ?\', [$value])',
|
||||
'laravel.db_raw' => 'DB::raw() に変数が含まれています。SQLインジェクションのリスクがあります。',
|
||||
'laravel.db_raw.rec' => 'パラメータバインディングを使用するか、DB::raw() でのユーザー入力の使用を避けてください。',
|
||||
'laravel.csrf_missing' => 'POST/PUT/PATCH/DELETE フォームに CSRF 保護がありません。',
|
||||
'laravel.csrf_missing.rec' => 'フォーム内に @csrf ディレクティブを追加してください。',
|
||||
'laravel.file_validation' => 'ファイルフィールド \':field\' は extensions のみで検証されています。MIMEタイプの検証がありません。',
|
||||
'laravel.file_validation.rec' => 'mimes または mimetypes ルールを追加してください: \'file|mimes:jpg,png\'',
|
||||
'laravel.route_auth' => 'センシティブなルート \':route\' に認証ミドルウェアがない可能性があります。',
|
||||
'laravel.route_auth.rec' => 'middleware(\'auth\') または middleware(\'auth:sanctum\') を追加してください。',
|
||||
'laravel.route_throttle' => '認証関連ルート \':route\' にレート制限がない可能性があります。',
|
||||
'laravel.route_throttle.rec' => 'ブルートフォース攻撃を防ぐために middleware(\'throttle:login\') を追加してください。',
|
||||
|
||||
// Report messages
|
||||
'report.title' => 'セキュリティスキャン結果',
|
||||
'report.generated' => '生成日時',
|
||||
@@ -537,6 +556,25 @@ class Messages
|
||||
'config.env_no_default' => 'env() called without default value may cause issues if variable is missing.',
|
||||
'config.env_no_default.rec' => 'Provide a default value: env(\'KEY\', \'default\')',
|
||||
|
||||
// Laravel-specific messages
|
||||
'laravel.name' => 'Laravel Security',
|
||||
'laravel.mass_assignment' => 'Eloquent model \':class\' has no $fillable or $guarded property defined. Vulnerable to Mass Assignment attacks.',
|
||||
'laravel.mass_assignment.rec' => 'Define protected $fillable = [...] or protected $guarded = [...] in the model.',
|
||||
'laravel.mass_assignment_all' => ':method() uses $request->all(). Risk of Mass Assignment attack.',
|
||||
'laravel.mass_assignment_all.rec' => 'Use $request->only([\'field1\', \'field2\']) or $request->validated() instead.',
|
||||
'laravel.raw_sql' => ':method() uses raw SQL without parameter binding. Risk of SQL injection.',
|
||||
'laravel.raw_sql.rec' => 'Use bindings: ->:method(\'column = ?\', [$value])',
|
||||
'laravel.db_raw' => 'DB::raw() contains variables. Risk of SQL injection.',
|
||||
'laravel.db_raw.rec' => 'Use parameter bindings or avoid user input in DB::raw().',
|
||||
'laravel.csrf_missing' => 'POST/PUT/PATCH/DELETE form is missing CSRF protection.',
|
||||
'laravel.csrf_missing.rec' => 'Add @csrf directive inside the form.',
|
||||
'laravel.file_validation' => 'File field \':field\' is validated with extensions only. Missing MIME type validation.',
|
||||
'laravel.file_validation.rec' => 'Add mimes or mimetypes rule: \'file|mimes:jpg,png\'',
|
||||
'laravel.route_auth' => 'Sensitive route \':route\' may be missing authentication middleware.',
|
||||
'laravel.route_auth.rec' => 'Add middleware(\'auth\') or middleware(\'auth:sanctum\').',
|
||||
'laravel.route_throttle' => 'Auth-related route \':route\' may be missing rate limiting.',
|
||||
'laravel.route_throttle.rec' => 'Add middleware(\'throttle:login\') to prevent brute force attacks.',
|
||||
|
||||
// Report messages
|
||||
'report.title' => 'Security Scan Results',
|
||||
'report.generated' => 'Generated',
|
||||
|
||||
@@ -299,7 +299,7 @@ HTML;
|
||||
'tool' => [
|
||||
'driver' => [
|
||||
'name' => 'PHP/Laravel Security Linter',
|
||||
'version' => '1.0.0',
|
||||
'version' => '0.0.1',
|
||||
],
|
||||
],
|
||||
'results' => $results,
|
||||
|
||||
Reference in New Issue
Block a user