mirror of
https://github.com/Nezumi-2711/google-drive-s3.git
synced 2026-09-22 13:38:30 +00:00
Improve security
This commit is contained in:
+81
-3
@@ -6,9 +6,8 @@
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||
try {
|
||||
const isValid = await verifySignature(request, env);
|
||||
if (!isValid) {
|
||||
return new Response("Invalid Signature", { status: 403 });
|
||||
if (request.method === "OPTIONS") {
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
@@ -19,6 +18,19 @@ export default {
|
||||
const bucket = pathParts[0] || "";
|
||||
const objectKey = pathParts.slice(1).join("/");
|
||||
|
||||
if (!isValidPath(bucket, objectKey)) {
|
||||
return new Response("Invalid path", { status: 400 });
|
||||
}
|
||||
|
||||
if (!isAllowedBucket(bucket, env)) {
|
||||
return new Response("Access denied to this bucket", { status: 403 });
|
||||
}
|
||||
|
||||
const isValid = await verifySignature(request, env);
|
||||
if (!isValid) {
|
||||
return new Response("Invalid Signature", { status: 403 });
|
||||
}
|
||||
|
||||
const accessToken = await getAccessToken(env);
|
||||
|
||||
if (method === "PUT" || method === "POST") {
|
||||
@@ -125,6 +137,7 @@ interface Env {
|
||||
GOOGLE_REFRESH_TOKEN: string;
|
||||
AUTH_KV: KVNamespace;
|
||||
FOLDER_CACHE: KVNamespace;
|
||||
ALLOWED_BUCKETS?: string;
|
||||
}
|
||||
|
||||
interface GoogleDriveFile {
|
||||
@@ -139,6 +152,71 @@ interface GoogleDriveSearchResponse {
|
||||
files?: GoogleDriveFile[];
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Security Functions
|
||||
// ========================================
|
||||
|
||||
function isValidPath(bucket: string, objectKey: string): boolean {
|
||||
// バケット名の検証
|
||||
if (!bucket || bucket.includes("..") || bucket.includes("/") || bucket.includes("\\")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// オブジェクトキーの検証
|
||||
if (objectKey) {
|
||||
// ".." を含むパスを拒否
|
||||
if (objectKey.includes("..")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// バックスラッシュを含むパスを拒否 (Windowsスタイルのパス)
|
||||
if (objectKey.includes("\\")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 絶対パスを拒否
|
||||
if (objectKey.startsWith("/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// パスの各コンポーネントを検証
|
||||
const parts = objectKey.split("/");
|
||||
for (const part of parts) {
|
||||
// 空のコンポーネントや "." を拒否
|
||||
if (!part || part === "." || part === "..") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NULLバイトを拒否
|
||||
if (part.includes("\0")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isAllowedBucket(bucket: string, env: Env): boolean {
|
||||
console.log(bucket);
|
||||
// 許可リストが設定されていない場合はすべて拒否
|
||||
if (!env.ALLOWED_BUCKETS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const allowedBuckets = env.ALLOWED_BUCKETS.split(",")
|
||||
.map((b) => b.trim())
|
||||
.filter((b) => b);
|
||||
|
||||
// 空の許可リストの場合もすべて拒否
|
||||
if (allowedBuckets.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// バケット名が許可リストに含まれているかチェック
|
||||
return allowedBuckets.includes(bucket);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Google Drive API Functions
|
||||
// ========================================
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ const ENV = {
|
||||
GOOGLE_REFRESH_TOKEN: "test-refresh-token",
|
||||
AUTH_KV: createMockKV(),
|
||||
FOLDER_CACHE: createMockKV(),
|
||||
ALLOWED_BUCKETS: "test-bucket,empty-bucket,my-bucket",
|
||||
};
|
||||
|
||||
const CTX = {
|
||||
@@ -222,7 +223,7 @@ describe("S3 API Server with Google Drive Backend", () => {
|
||||
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: "my-bucket",
|
||||
Key: "test.png",
|
||||
Key: "my-bucket/test.png",
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
|
||||
|
||||
Reference in New Issue
Block a user