Skip to content

Commit f85a684

Browse files
committed
fix: 권한 상승 취약점 패치
1 parent f2ea0c3 commit f85a684

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { NextResponse } from 'next/server';
2+
import type { NextRequest } from 'next/server';
3+
import { createServerClient } from '@supabase/ssr';
4+
import { Database } from '@/src/app/types/database.types';
5+
import { createClient } from '@supabase/supabase-js';
6+
7+
export async function POST(request: NextRequest){
8+
const body = await request.json().catch()
9+
10+
// 유효하지 않은 데이터는 그냥 반환
11+
if (!body){
12+
return NextResponse.json({
13+
data: null,
14+
error: "invalid data"
15+
})
16+
}
17+
18+
const {nickname}: {nickname: string} = body;
19+
if (!nickname){
20+
return NextResponse.json({
21+
data: null,
22+
error: "invalid data"
23+
})
24+
}
25+
26+
// 요청자의 데이터를 쿠키에서 얻어냄
27+
let supabaseResponse = NextResponse.next({request,})
28+
29+
const supabase = createServerClient<Database>(
30+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
31+
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
32+
{
33+
cookies: {
34+
getAll() {
35+
return request.cookies.getAll()
36+
},
37+
setAll(cookiesToSet) {
38+
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
39+
supabaseResponse = NextResponse.next({
40+
request,
41+
})
42+
cookiesToSet.forEach(({ name, value, options }) =>
43+
supabaseResponse.cookies.set(name, value, options)
44+
)
45+
},
46+
},
47+
}
48+
)
49+
50+
// 유효한 유저인지 검사
51+
const { data: { user } } = await supabase.auth.getUser();
52+
if (!user){
53+
return NextResponse.json({
54+
data: null,
55+
error: "no session"
56+
})
57+
}
58+
59+
// 업데이트 처리
60+
const supabaseServer = createClient<Database>(
61+
process.env.NEXT_PUBLIC_SUPABASE_URL,
62+
process.env.SUPABASE_SERVICE_KEY
63+
)
64+
const {data, error} = await supabaseServer.from('users').insert({id: user.id, nickname: nickname.trim()}).select('*').maybeSingle();
65+
if (error){
66+
return NextResponse.json({
67+
data,
68+
error
69+
},{status:500})
70+
}
71+
return NextResponse.json({
72+
data,
73+
error
74+
})
75+
}

src/app/auth/auth.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const AuthPage = () => {
124124
}
125125

126126
// 닉네임 등록
127-
const { data, error:err } = await SCM.add().nickname(session.data.session.user.id, nickname)
127+
const { data, error:err } = await SCM.add().nickname(nickname)
128128

129129
if (err) {
130130
setErrorModalView({

src/app/lib/supabase/ISupabaseClientManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export interface IAddManager {
3333
waitWordThemes(insertWaitWordThemeData: { wait_word_id: number; theme_id: number; }[]): Promise<PostgrestSingleResponse<null>>
3434
waitDocs({ docsName, userId }: { docsName: string; userId: string | undefined; }): Promise<PostgrestSingleResponse<null>>;
3535
docs(insertDocsData: { name: string; maker: string | null; duem: boolean; typez: "letter" | "theme"; }[]): Promise<PostgrestSingleResponse<null>>;
36-
nickname(userId: string, nick: string): Promise<PostgrestSingleResponse<user>>;
36+
nickname(nick: string): Promise<PostgrestSingleResponse<user>>;
3737
words(q:addWordQueryType[]): Promise<PostgrestSingleResponse<word[]>>;
3838
wordsThemes(q: addWordThemeQueryType[]): Promise<PostgrestSingleResponse<{words:{word: string}; themes: {name: string}}[]>>;
3939
wordThemesReq(q: {word_id: number, theme_id: number, typez: "add" | "delete", req_by: string | null}[]): Promise<PostgrestSingleResponse<{typez: "add" | "delete"; themes:{name: string}}[]>>

src/app/lib/supabase/SupabaseClientManager.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import DuemLaw, { reverDuemLaw } from '../hangulUtils';
66
import { sum } from 'es-toolkit';
77
import { StorageError } from '@supabase/storage-js';
88
import { misssionCharMask } from '../lib';
9+
import axios from 'axios';
910

1011
const CACHE_DURATION = 10 * 60 * 1000;
1112

@@ -53,8 +54,9 @@ class AddManager implements IAddManager {
5354
public async docs(docsInserQuery: { name: string, maker: string | null, duem: boolean, typez: "letter" }[]) {
5455
return await this.supabase.from('docs').insert(docsInserQuery);
5556
}
56-
public async nickname(userId: string, nick: string) {
57-
return this.supabase.from("users").insert({ id: userId, nickname: nick.trim() }).select("*").single();
57+
public async nickname(nick: string) {
58+
const res = await axios.post('/api/auth/set_nickname', { nickname: nick.trim() });
59+
return res.data;
5860
}
5961
public async words(q: addWordQueryType[]) {
6062
return this.supabase.from('words').upsert(q, { ignoreDuplicates: true, onConflict: "word" }).select('*');

0 commit comments

Comments
 (0)