{"id":2667,"date":"2026-10-24T08:54:11","date_gmt":"2026-10-24T08:54:11","guid":{"rendered":"https:\/\/wayhope.kro.kr\/?p=2667"},"modified":"2026-10-24T08:54:11","modified_gmt":"2026-10-24T08:54:11","slug":"%ec%b6%94%ea%b0%80-%ec%9d%b8%ec%a6%9d-%ec%84%a4%ea%b3%84-2%eb%8b%a8%ea%b3%84-%ec%9d%b8%ec%a6%9d2fa-%ec%9d%b8%ec%a6%9d-%ec%bd%94%eb%93%9c-%ea%b4%80%eb%a6%ac-%ec%8b%9c%eb%8f%84-%ec%a0%9c%ed%95%9c","status":"publish","type":"post","link":"https:\/\/wayhope.kro.kr\/?p=2667","title":{"rendered":"\ucd94\uac00 \uc778\uc99d \uc124\uacc4 #2\ub2e8\uacc4 \uc778\uc99d(2FA), \uc778\uc99d \ucf54\ub4dc \uad00\ub9ac, \uc2dc\ub3c4 \uc81c\ud55c, \uacc4\uc815 \ud0c8\ucde8 \ub300\uc751"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\ud68c\uc6d0\uac00\uc785\uacfc \ub85c\uadf8\uc778\uc5d0 \uc544\uc774\ub514\uc640 \ube44\ubc00\ubc88\ud638\ub9cc \uc0ac\uc6a9\ud558\ub294 \uc2dc\uc2a4\ud15c\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc720\ucd9c\ub418\ub294 \uc21c\uac04 \uacc4\uc815\uc774 \ud0c8\ucde8\ub420 \uc218 \uc788\ub2e4. \ube44\ubc00\ubc88\ud638\uac00 \uc548\uc804\ud558\uac8c \ud574\uc2f1\ub418\uc5b4 \uc788\ub354\ub77c\ub3c4 \uc0ac\uc6a9\uc790\uac00 \ud53c\uc2f1 \uc0ac\uc774\ud2b8\uc5d0 \uc785\ub825\ud558\uac70\ub098 \ub2e4\ub978 \uc11c\ube44\uc2a4\uc5d0\uc11c \uc7ac\uc0ac\uc6a9\ud55c \ube44\ubc00\ubc88\ud638\uac00 \uc720\ucd9c\ub418\uba74 \uc778\uc99d \uccb4\uacc4 \uc790\uccb4\uac00 \ubb34\ub825\ud654\ub420 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774\ub97c \ubcf4\uc644\ud558\uae30 \uc704\ud574 \uc0ac\uc6a9\ud558\ub294 \uac83\uc774 <strong>\ucd94\uac00 \uc778\uc99d(Multi-Factor Authentication, MFA)<\/strong> \uc774\ub2e4. \ucd94\uac00 \uc778\uc99d\uc740 \ube44\ubc00\ubc88\ud638 \uc678\uc5d0 \ubcc4\ub3c4\uc758 \uc778\uc99d \uc218\ub2e8\uc744 \uc694\uad6c\ud558\uc5ec \uacc4\uc815 \uc811\uadfc\uc5d0 \ud544\uc694\ud55c \ubcf4\uc548 \uc218\uc900\uc744 \ub192\uc778\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ucd94\uac00 \uc778\uc99d \uc2dc\uc2a4\ud15c\uc744 \uc124\uacc4\ud560 \ub54c\ub294 \ub2e4\uc74c \ud56d\ubaa9\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2\ub2e8\uacc4 \uc778\uc99d(2FA)<\/li>\n\n\n\n<li>\uc778\uc99d \ucf54\ub4dc \uc0dd\uc131 \ubc0f \ub9cc\ub8cc \uc2dc\uac04 \uad00\ub9ac<\/li>\n\n\n\n<li>\uc778\uc99d \uc2dc\ub3c4 \ud69f\uc218 \uc81c\ud55c<\/li>\n\n\n\n<li>\uacc4\uc815 \ud0c8\ucde8 \ud0d0\uc9c0 \ubc0f \ub300\uc751<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ud575\uc2ec\uc740 \uc778\uc99d \ucf54\ub4dc\ub97c \ubc1c\uae09\ud558\ub294 \uac83\ub9cc\uc774 \uc544\ub2c8\ub2e4. \ucf54\ub4dc\ub97c \uc548\uc804\ud558\uac8c \uc0dd\uc131\ud558\uace0, \uac80\uc99d\ud558\uace0, \uc18c\ube44\ud558\uace0, \uc2e4\ud328 \uc0c1\ud669\uc744 \ud1b5\uc81c\ud558\ub294 \uc804\uccb4 \uacfc\uc815\uc744 \uc124\uacc4\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2\ub2e8\uacc4 \uc778\uc99d(2FA)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2\ub2e8\uacc4 \uc778\uc99d\uc774\ub780?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">2\ub2e8\uacc4 \uc778\uc99d(Two-Factor Authentication, 2FA)\uc740 \ub85c\uadf8\uc778 \uacfc\uc815\uc5d0\uc11c \uc11c\ub85c \ub2e4\ub978 \ub450 \uac00\uc9c0 \uc778\uc99d \uc694\uc18c\ub97c \uc694\uad6c\ud558\ub294 \ubc29\uc2dd\uc774\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \uc694\uc18c\ub294 \uc77c\ubc18\uc801\uc73c\ub85c \ub2e4\uc74c \uc138 \uac00\uc9c0\ub85c \uad6c\ubd84\ud55c\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>\uc778\uc99d \uc694\uc18c<\/th><th>\uc124\uba85<\/th><th>\uc608\uc2dc<\/th><\/tr><tr><td>\uc9c0\uc2dd \uae30\ubc18<\/td><td>\uc0ac\uc6a9\uc790\uac00 \uc54c\uace0 \uc788\ub294 \uc815\ubcf4<\/td><td>\ube44\ubc00\ubc88\ud638, PIN<\/td><\/tr><tr><td>\uc18c\uc720 \uae30\ubc18<\/td><td>\uc0ac\uc6a9\uc790\uac00 \uc18c\uc720\ud55c \uae30\uae30\ub098 \uc218\ub2e8<\/td><td>\uc778\uc99d \uc571, \ubcf4\uc548 \ud0a4<\/td><\/tr><tr><td>\uc0dd\uccb4 \uae30\ubc18<\/td><td>\uc0ac\uc6a9\uc790\uc758 \uc0dd\uccb4\uc801 \ud2b9\uc131<\/td><td>\uc9c0\ubb38, \uc5bc\uad74 \uc778\uc2dd<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\uc11c\ub85c \ub2e4\ub978 \uc694\uc18c\ub97c \ub450 \uac00\uc9c0 \uc774\uc0c1 \uc0ac\uc6a9\ud574\uc57c \uc9c4\uc815\ud55c \uc758\ubbf8\uc758 \ub2e4\uc911 \uc694\uc18c \uc778\uc99d\uc774 \ub41c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \ube44\ubc00\ubc88\ud638\uc640 \ubcc4\ub3c4\uc758 \ube44\ubc00\ubc88\ud638\ub97c \uc694\uad6c\ud558\ub294 \uac83\uc740 \uc778\uc99d \uc815\ubcf4\uac00 \ub450 \uac1c\uc77c \ubfd0, \ubc18\ub4dc\uc2dc 2FA\uac00 \ub418\ub294 \uac83\uc740 \uc544\ub2c8\ub2e4. \ubc18\uba74 \ube44\ubc00\ubc88\ud638\uc640 \uc778\uc99d \uc571\uc5d0\uc11c \uc0dd\uc131\ud55c \uc77c\ud68c\uc6a9 \ucf54\ub4dc\ub97c \ud568\uaed8 \uc0ac\uc6a9\ud558\uba74 \uc11c\ub85c \ub2e4\ub978 \uc778\uc99d \uc694\uc18c\ub97c \uacb0\ud569\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2FA \ubc29\uc2dd\uc758 \uc885\ub958<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\uc774\uba54\uc77c \uc778\uc99d \ucf54\ub4dc<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc0ac\uc6a9\uc790\uac00 \ub85c\uadf8\uc778\ud558\uba74 \ub4f1\ub85d\ub41c \uc774\uba54\uc77c \uc8fc\uc18c\ub85c \uc778\uc99d \ucf54\ub4dc\ub97c \uc804\uc1a1\ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\uad6c\ud604\uc774 \ube44\uad50\uc801 \uac04\ub2e8\ud558\ub2e4.<\/li>\n\n\n\n<li>\uc774\uba54\uc77c \uacc4\uc815\uc774 \ud0c8\ucde8\ub418\uba74 \ucd94\uac00 \uc778\uc99d\ub3c4 \ubb34\ub825\ud654\ub420 \uc218 \uc788\ub2e4.<\/li>\n\n\n\n<li>\uc774\uba54\uc77c\uc740 \ubcc4\ub3c4\uc758 \uc778\uc99d \uc694\uc18c\ub85c \ubd84\ub958\ud560 \ub54c \uc8fc\uc758\uac00 \ud544\uc694\ud558\ub2e4. \uc774\uba54\uc77c \uacc4\uc815\uc758 \uc811\uadfc \uc218\ub2e8\uc774 \uac19\uc740 \ube44\ubc00\ubc88\ud638\uc5d0 \uc758\uc874\ud55c\ub2e4\uba74 \uc778\uc99d \ub3c5\ub9bd\uc131\uc774 \uc57d\ud574\uc9c4\ub2e4.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>SMS \uc778\uc99d \ucf54\ub4dc<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud734\ub300\uc804\ud654 \ubc88\ud638\ub85c \uc77c\ud68c\uc6a9 \uc778\uc99d \ucf54\ub4dc\ub97c \uc804\uc1a1\ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\uc0ac\uc6a9\uc790\uc5d0\uac8c \uc775\uc219\ud558\uace0 \uc0ac\uc6a9\ud558\uae30 \uc27d\ub2e4.<\/li>\n\n\n\n<li>SIM \uc2a4\uc640\ud551, \ubb38\uc790 \uac00\ub85c\ucc44\uae30, \uc804\ud654\ubc88\ud638 \ud0c8\ucde8 \ub4f1\uc758 \uc704\ud5d8\uc774 \uc788\ub2e4.<\/li>\n\n\n\n<li>\ubb38\uc790 \ubc1c\uc1a1 \ube44\uc6a9\uacfc \ubc1c\uc1a1\ub7c9 \uc81c\ud55c\uc744 \uace0\ub824\ud574\uc57c \ud55c\ub2e4.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\uc778\uc99d \uc571 \uae30\ubc18 TOTP<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Google Authenticator\uc640 \uac19\uc740 \uc778\uc99d \uc571\uc774 \uc2dc\uac04 \uae30\ubc18 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638(Time-based One-Time Password)\ub97c \uc0dd\uc131\ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ubcc4\ub3c4\uc758 \ubb38\uc790 \ubc1c\uc1a1 \ube44\uc6a9\uc774 \uc5c6\ub2e4.<\/li>\n\n\n\n<li>\ub124\ud2b8\uc6cc\ud06c \uc5f0\uacb0 \uc5c6\uc774\ub3c4 \ucf54\ub4dc\ub97c \uc0dd\uc131\ud560 \uc218 \uc788\ub2e4.<\/li>\n\n\n\n<li>\uc11c\ubc84\uc640 \uc778\uc99d \uc571\uc774 \uacf5\uc720\ud558\ub294 \ube44\ubc00\ud0a4\ub97c \uc548\uc804\ud558\uac8c \uad00\ub9ac\ud574\uc57c \ud55c\ub2e4.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ubcf4\uc548 \ud0a4 \ubc0f \ud328\uc2a4\ud0a4<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">FIDO2\/WebAuthn \uae30\ubc18 \uc778\uc99d\uc740 \ud53c\uc2f1\uc5d0 \uac15\ud55c \uc778\uc99d \uc218\ub2e8\uc744 \uc81c\uacf5\ud55c\ub2e4. \ud2b9\ud788 \ud328\uc2a4\ud0a4\ub294 \ube44\ubc00\ubc88\ud638 \uc758\uc874\ub3c4\ub97c \uc904\uc774\uba74\uc11c \uc0ac\uc6a9\uc790 \uae30\uae30\uc758 \uc778\uc99d \uae30\ub2a5\uc744 \ud65c\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ubcf4\uc548 \uc218\uc900\uc774 \uc911\uc694\ud55c \uc11c\ube44\uc2a4\ub77c\uba74 SMS\ub098 \uc774\uba54\uc77c \ucf54\ub4dc\ub9cc\uc73c\ub85c \ubaa8\ub4e0 \uc778\uc99d\uc744 \ud574\uacb0\ud558\uae30\ubcf4\ub2e4 \uc778\uc99d \uc571, \ubcf4\uc548 \ud0a4, \ud328\uc2a4\ud0a4 \ub4f1\uc758 \ub3c4\uc785\uc744 \uac80\ud1a0\ud558\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2FA\uc758 \uae30\ubcf8 \ub3d9\uc791 \ud750\ub984<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ub85c\uadf8\uc778 \uacfc\uc815\uc5d0\uc11c \ucd94\uac00 \uc778\uc99d\uc774 \ud544\uc694\ud55c \uacbd\uc6b0, \ube44\ubc00\ubc88\ud638 \uac80\uc99d\uc774 \uc131\uacf5\ud588\ub2e4\uace0 \ud574\uc11c \ubc14\ub85c \ub85c\uadf8\uc778 \uc138\uc158\uc744 \ubc1c\uae09\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\ud074\ub77c\uc774\uc5b8\ud2b8\n   |\n   | POST \/auth\/login\n   | \uc774\uba54\uc77c + \ube44\ubc00\ubc88\ud638\n   v\n\uc778\uc99d \uc11c\ubc84\n   |\n   | \ube44\ubc00\ubc88\ud638 \uac80\uc99d \uc131\uacf5\n   v\n\ucd94\uac00 \uc778\uc99d \ud544\uc694 \uc5ec\ubd80 \ud655\uc778\n   |\n   | \uc778\uc99d \uc808\ucc28 \uc2dc\uc791\n   v\n\uc778\uc99d \ucf54\ub4dc \ubc1c\uae09 \ub610\ub294 TOTP \uac80\uc99d \uc900\ube44\n   |\n   | POST \/auth\/2fa\/verify\n   | \uc778\uc99d \ucf54\ub4dc \uc81c\ucd9c\n   v\n\uc778\uc99d \uc11c\ubc84\n   |\n   | \ucf54\ub4dc \uac80\uc99d \ubc0f \uc0ac\uc6a9 \ucc98\ub9ac\n   v\n\ucd5c\uc885 \ub85c\uadf8\uc778 \uc138\uc158 \ub610\ub294 \ud1a0\ud070 \ubc1c\uae09<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \uacfc\uc815\uc5d0\uc11c \uc911\uc694\ud55c \uc810\uc740 <strong>\ucd94\uac00 \uc778\uc99d\uc774 \uc644\ub8cc\ub418\uae30 \uc804\uc5d0\ub294 \uc77c\ubc18\uc801\uc778 \uc11c\ube44\uc2a4 \uc811\uadfc \uad8c\ud55c\uc744 \ubd80\uc5ec\ud558\uc9c0 \uc54a\ub294 \uac83<\/strong>\uc774\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uccab \ubc88\uc9f8 \uc778\uc99d\uc5d0 \uc131\uacf5\ud55c \uc0ac\uc6a9\uc790\ub294 \uc544\uc9c1 \uc644\uc804\ud788 \uc778\uc99d\ub41c \uc0ac\uc6a9\uc790\uac00 \uc544\ub2c8\ub2e4. \ub530\ub77c\uc11c \uc81c\ud55c\ub41c \uc778\uc99d \uc0c1\ud0dc\ub97c \ub098\ud0c0\ub0b4\ub294 \uc784\uc2dc \ud1a0\ud070\uc774\ub098 \uc11c\ubc84 \uce21 \uc778\uc99d \ud2b8\ub79c\uc7ad\uc158\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc784\uc2dc \ud1a0\ud070\uc740 \uc77c\ubc18 Access Token\uacfc \uad6c\ubd84\ud558\uace0, \ucd5c\uc885 \uc778\uc99d API \uc678\uc5d0\ub294 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\ub3c4\ub85d \uc81c\ud55c\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc \uc0dd\uc131 \ubc0f \ub9cc\ub8cc \uc2dc\uac04<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc\ub294 \uc5b4\ub5bb\uac8c \uc0dd\uc131\ud574\uc57c \ud558\ub294\uac00?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\ub294 \ucd94\uce21\ud558\uae30 \uc5b4\ub824\uc6cc\uc57c \ud558\uba70, \uacf5\uaca9\uc790\uac00 \ub3d9\uc77c\ud55c \ucf54\ub4dc\ub97c \ubc18\ubcf5\ud574\uc11c \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\ub294 \ubcf4\uc548 \ubaa9\uc801\uc5d0 \uc801\ud569\ud55c \uc554\ud638\ud559\uc801 \ub09c\uc218 \uc0dd\uc131\uae30(CSPRNG)\ub97c \uc0ac\uc6a9\ud574 \uc0dd\uc131\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Node.js\uc5d0\uc11c\ub294 <code>crypto<\/code> \ubaa8\ub4c8\uc758 <code>randomInt()<\/code>\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { randomInt } from \"node:crypto\";\n\nfunction generateVerificationCode(): string {\n  return randomInt(0, 1_000_000)\n    .toString()\n    .padStart(6, \"0\");\n}\n\nconst code = generateVerificationCode();\n\nconsole.log(code); \/\/ \uc608: 042817<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \ucf54\ub4dc\ub294 <code>000000<\/code>\ubd80\ud130 <code>999999<\/code>\uae4c\uc9c0\uc758 \uc5ec\uc12f \uc790\ub9ac \uc22b\uc790\ub97c \uc0dd\uc131\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc5ec\uc12f \uc790\ub9ac \ucf54\ub4dc\ub294 \ucd1d 1,000,000\uac00\uc9c0 \uacbd\uc6b0\uc758 \uc218\ub97c \uac00\uc9c0\ubbc0\ub85c, \uacf5\uaca9\uc790\uac00 \ubc18\ubcf5\uc801\uc73c\ub85c \uc2dc\ub3c4\ud560 \uc218 \uc788\ub2e4\uba74 \ubb34\ucc28\ubcc4 \ub300\uc785 \uacf5\uaca9\uc5d0 \ucde8\uc57d\ud574\uc9c8 \uc218 \uc788\ub2e4. \ub530\ub77c\uc11c \ucf54\ub4dc\uc758 \uae38\uc774\ubfd0 \uc544\ub2c8\ub77c \ub9cc\ub8cc \uc2dc\uac04\uacfc \uc2dc\ub3c4 \ud69f\uc218 \uc81c\ud55c\uc744 \ud568\uaed8 \uc124\uacc4\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \uc0dd\uc131 \uc2dc <code>Math.random()<\/code>\uc744 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\ub294 \uac83\uc774 \uc88b\ub2e4. \uc77c\ubc18\uc801\uc778 \ub09c\uc218 \uc0dd\uc131 \ubaa9\uc801\uc5d0\ub294 \uc0ac\uc6a9\ud560 \uc218 \uc788\uc9c0\ub9cc, \uc778\uc99d \uc815\ubcf4\ucc98\ub7fc \uc608\uce21 \uac00\ub2a5\uc131\uc774 \ubcf4\uc548\uc5d0 \uc601\ud5a5\uc744 \uc8fc\ub294 \uc601\uc5ed\uc5d0\ub294 \uc554\ud638\ud559\uc801 \ub09c\uc218 \uc0dd\uc131\uae30\ub97c \uc0ac\uc6a9\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc\uc5d0 \ub9cc\ub8cc \uc2dc\uac04\uc774 \ud544\uc694\ud55c \uc774\uc720<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\uac00 \uc601\uad6c\uc801\uc73c\ub85c \uc720\ud6a8\ud558\ub2e4\uba74 \uacfc\uac70\uc5d0 \ubc1c\uae09\ub41c \ucf54\ub4dc\uac00 \uc720\ucd9c\ub418\uc5c8\uc744 \ub54c\ub3c4 \uacc4\uc815 \uc811\uadfc\uc5d0 \uc0ac\uc6a9\ub420 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub530\ub77c\uc11c \uc778\uc99d \ucf54\ub4dc\uc5d0\ub294 \uc720\ud6a8 \uae30\uac04\uc744 \uc124\uc815\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \uc774\uba54\uc77c \uc778\uc99d \ucf54\ub4dc\ub97c \ubc1c\uae09\ud55c \uc2dc\uc810\ubd80\ud130 5\ubd84 \ub3d9\uc548\ub9cc \uc720\ud6a8\ud558\ub3c4\ub85d \uc124\uc815\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \ub370\uc774\ud130\ub294 \ub2e4\uc74c\uacfc \uac19\uc774 \uad00\ub9ac\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>interface VerificationCode {\n  userId: string;\n  codeHash: string;\n  expiresAt: number;\n  attempts: number;\n  consumed: boolean;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uac01 \ud544\ub4dc\uc758 \uc5ed\ud560\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>userId<\/code>: \uc778\uc99d \ub300\uc0c1 \uc0ac\uc6a9\uc790<\/li>\n\n\n\n<li><code>codeHash<\/code>: \uc778\uc99d \ucf54\ub4dc\uc758 \uac80\uc99d\uc6a9 \ud574\uc2dc<\/li>\n\n\n\n<li><code>expiresAt<\/code>: \ub9cc\ub8cc \uc2dc\uac01<\/li>\n\n\n\n<li><code>attempts<\/code>: \uc778\uc99d \uc2dc\ub3c4 \ud69f\uc218<\/li>\n\n\n\n<li><code>consumed<\/code>: \uc774\ubbf8 \uc0ac\uc6a9\ub418\uc5c8\ub294\uc9c0 \uc5ec\ubd80<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uc2e4\uc81c \uc6b4\uc601 \ud658\uacbd\uc5d0\uc11c\ub294 \uc774 \ub370\uc774\ud130\ub97c Redis\uc640 \uac19\uc740 \uc800\uc7a5\uc18c\uc5d0 \ubcf4\uad00\ud560 \uc218 \uc788\ub2e4. \ub9cc\ub8cc \uc2dc\uac01\uc740 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc5d0\uc11c \uac80\uc99d\ud558\uace0, Redis\uc758 TTL\uc744 \uc124\uc815\ud558\uc5ec \ub9cc\ub8cc\ub41c \ub370\uc774\ud130\ub97c \uc790\ub3d9\uc73c\ub85c \uc815\ub9ac\ud560 \uc218\ub3c4 \uc788\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc\ub97c \ud3c9\ubb38\uc73c\ub85c \uc800\uc7a5\ud558\uc9c0 \uc54a\uae30<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\uac00 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub098 Redis\uc5d0 \ud3c9\ubb38\uc73c\ub85c \uc800\uc7a5\ub418\uc5b4 \uc788\ub2e4\uba74 \uc800\uc7a5\uc18c\uac00 \uc720\ucd9c\ub418\uc5c8\uc744 \ub54c \uacf5\uaca9\uc790\uac00 \ucf54\ub4dc\ub97c \uadf8\ub300\ub85c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub530\ub77c\uc11c \uc778\uc99d \ucf54\ub4dc \ub300\uc2e0 \uac80\uc99d\uc6a9 \ud574\uc2dc\ub97c \uc800\uc7a5\ud558\ub294 \ubc29\uc2dd\uc744 \uace0\ub824\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { createHash } from \"node:crypto\";\n\nfunction hashVerificationCode(code: string): string {\n  return createHash(\"sha256\")\n    .update(code)\n    .digest(\"hex\");\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\ucf54\ub4dc\ub97c \uac80\uc99d\ud560 \ub54c\ub294 \uc0ac\uc6a9\uc790\uac00 \uc785\ub825\ud55c \ucf54\ub4dc\uc758 \ud574\uc2dc\ub97c \uacc4\uc0b0\ud55c \ub4a4 \uc800\uc7a5\ub41c \ud574\uc2dc\uc640 \ube44\uad50\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub2e4\ub9cc \uc5ec\uc12f \uc790\ub9ac \uc22b\uc790\ub294 \uacbd\uc6b0\uc758 \uc218\uac00 \ub9e4\uc6b0 \uc801\uae30 \ub54c\ubb38\uc5d0 \uc77c\ubc18\uc801\uc778 SHA-256 \ud574\uc2dc\ub9cc\uc73c\ub85c\ub294 \uc624\ud504\ub77c\uc778 \ubb34\ucc28\ubcc4 \ub300\uc785 \uacf5\uaca9\uc744 \ucda9\ubd84\ud788 \ubc29\uc5b4\ud560 \uc218 \uc5c6\ub2e4. \uc800\uc7a5\uc18c \uc720\ucd9c\uae4c\uc9c0 \uace0\ub824\ud55c\ub2e4\uba74 \uc11c\ubc84 \ube44\ubc00\ud0a4\ub97c \uc0ac\uc6a9\ud558\ub294 HMAC \uae30\ubc18 \uac80\uc99d\uac12\uc774\ub098 \ubcc4\ub3c4\uc758 \uc548\uc804\ud55c \ud0a4 \uad00\ub9ac \ubc29\uc2dd\uc744 \uac80\ud1a0\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \uac80\uc99d\uac12\uc744 \uc0dd\uc131\ud560 \ub54c \uc0ac\uc6a9\ud558\ub294 \ube44\ubc00\ud0a4\ub294 \ucf54\ub4dc\uc640 \ub3d9\uc77c\ud55c \uc800\uc7a5\uc18c\uc5d0 \ud568\uaed8 \ubcf4\uad00\ud558\uc9c0 \uc54a\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc\ub294 \ud55c \ubc88\ub9cc \uc0ac\uc6a9\ud560 \uc218 \uc788\uc5b4\uc57c \ud55c\ub2e4<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\uac00 \uc62c\ubc14\ub974\ub354\ub77c\ub3c4 \uc774\ubbf8 \uc0ac\uc6a9\ub41c \ucf54\ub4dc\ub77c\uba74 \uc778\uc99d\uc5d0 \uc131\uacf5\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \uc778\uc99d \ucf54\ub4dc\ub97c \uac80\uc99d\ud55c \ud6c4\uc5d0\ub3c4 \ud574\ub2f9 \ucf54\ub4dc\uac00 \uc800\uc7a5\uc18c\uc5d0 \ub0a8\uc544 \uc788\ub2e4\uba74 \uacf5\uaca9\uc790\uac00 \uac19\uc740 \ucf54\ub4dc\ub97c \uc7ac\uc804\uc1a1\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub530\ub77c\uc11c \uc778\uc99d \ucf54\ub4dc\ub294 \ub2e4\uc74c \uc870\uac74\uc744 \ub9cc\uc871\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ub9cc\ub8cc\ub418\uc9c0 \uc54a\uc558\uc744 \uac83<\/li>\n\n\n\n<li>\uc778\uc99d \ub300\uc0c1 \uc0ac\uc6a9\uc790\uc640 \uc77c\uce58\ud560 \uac83<\/li>\n\n\n\n<li>\uac80\uc99d\uc5d0 \uc131\uacf5\ud560 \uac83<\/li>\n\n\n\n<li>\uc774\uc804\uc5d0 \uc0ac\uc6a9\ub418\uc9c0 \uc54a\uc558\uc744 \uac83<\/li>\n\n\n\n<li>\ud5c8\uc6a9\ub41c \uc2dc\ub3c4 \ud69f\uc218\ub97c \ucd08\uacfc\ud558\uc9c0 \uc54a\uc558\uc744 \uac83<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uac80\uc99d\uc5d0 \uc131\uacf5\ud588\ub2e4\uba74 \ud574\ub2f9 \ucf54\ub4dc\ub97c \uc989\uc2dc \uc18c\ube44 \ucc98\ub9ac\ud574\uc57c \ud55c\ub2e4. \ub3d9\uc2dc\uc5d0 \uc5ec\ub7ec \uc694\uccad\uc774 \ub4e4\uc5b4\uc624\ub294 \uacbd\uc6b0\ub97c \uace0\ub824\ud558\uc5ec \uac80\uc99d\uacfc \uc18c\ube44 \ucc98\ub9ac\uac00 \uc6d0\uc790\uc801\uc73c\ub85c \uc774\ub8e8\uc5b4\uc9c0\ub3c4\ub85d \uc124\uacc4\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Redis\uc5d0\uc11c\ub294 Lua \uc2a4\ud06c\ub9bd\ud2b8\ub098 \uc6d0\uc790\uc801 \uba85\ub839\uc744 \ud65c\uc6a9\ud560 \uc218 \uc788\uace0, \uad00\uacc4\ud615 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c\ub294 \ud2b8\ub79c\uc7ad\uc158\uacfc \uc870\uac74\ubd80 \uc5c5\ub370\uc774\ud2b8\ub97c \ud65c\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\uc778\uc99d \uc2dc\ub3c4 \uc81c\ud55c<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc65c \uc2dc\ub3c4 \ud69f\uc218\ub97c \uc81c\ud55c\ud574\uc57c \ud558\ub294\uac00?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc5ec\uc12f \uc790\ub9ac \uc778\uc99d \ucf54\ub4dc\ub294 \uacbd\uc6b0\uc758 \uc218\uac00 \uc81c\ud55c\ub418\uc5b4 \uc788\ub2e4. \uacf5\uaca9\uc790\uac00 \ucd08\ub2f9 \uc218\ubc31 \ubc88\uc529 \ucf54\ub4dc\ub97c \uc785\ub825\ud560 \uc218 \uc788\ub2e4\uba74 \uc720\ud6a8\ud55c \ucf54\ub4dc\ub97c \ucd94\uce21\ud560 \uac00\ub2a5\uc131\uc774 \ucee4\uc9c4\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774\ub97c \ubc29\uc5b4\ud558\ub824\uba74 \uc778\uc99d \uc2dc\ub3c4 \ud69f\uc218\ub97c \uc81c\ud55c\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \ub2e4\uc74c\uacfc \uac19\uc740 \uc815\ucc45\uc744 \uc124\uc815\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>\uc81c\ud55c \ub300\uc0c1<\/th><th>\uc608\uc2dc \uc815\ucc45<\/th><\/tr><tr><td>\uc778\uc99d \ucf54\ub4dc\ubcc4<\/td><td>\ucd5c\ub300 5\ud68c \uc2e4\ud328<\/td><\/tr><tr><td>\uc0ac\uc6a9\uc790 \uacc4\uc815\ubcc4<\/td><td>\uc77c\uc815 \uc2dc\uac04 \ub3d9\uc548 \uc2e4\ud328 \ud69f\uc218 \uc81c\ud55c<\/td><\/tr><tr><td>IP \uc8fc\uc18c\ubcc4<\/td><td>\uc77c\uc815 \uc2dc\uac04 \ub3d9\uc548 \uc694\uccad \ud69f\uc218 \uc81c\ud55c<\/td><\/tr><tr><td>\ucf54\ub4dc \ubc1c\uae09 API<\/td><td>\uc7ac\ubc1c\uae09 \uac04\uaca9 \ubc0f \uc2dc\uac04\ub2f9 \ubc1c\uae09\ub7c9 \uc81c\ud55c<\/td><\/tr><tr><td>\ub85c\uadf8\uc778 API<\/td><td>\ube44\ubc00\ubc88\ud638 \uc2e4\ud328 \ud69f\uc218 \ubc0f \uc694\uccad \uc18d\ub3c4 \uc81c\ud55c<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\uc704 \uc218\uce58\ub294 \uc608\uc2dc\uc774\uba70, \uc2e4\uc81c \uc11c\ube44\uc2a4\uc758 \uc704\ud5d8\ub3c4\uc640 \uc0ac\uc6a9 \ud328\ud134\uc5d0 \ub530\ub77c \uc870\uc815\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc\ubcc4 \uc2dc\ub3c4 \uc81c\ud55c<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc\ub97c \ubc1c\uae09\ud560 \ub54c \uc2dc\ub3c4 \ud69f\uc218\ub97c 0\uc73c\ub85c \ucd08\uae30\ud654\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc0ac\uc6a9\uc790\uac00 \uc798\ubabb\ub41c \ucf54\ub4dc\ub97c \uc785\ub825\ud560 \ub54c\ub9c8\ub2e4 \ud69f\uc218\ub97c \uc99d\uac00\uc2dc\ud0a4\uace0, \uc81c\ud55c\uc744 \ucd08\uacfc\ud558\uba74 \ud574\ub2f9 \ucf54\ub4dc\ub97c \ub354 \uc774\uc0c1 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\ub3c4\ub85d \ucc98\ub9ac\ud55c\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const MAX_ATTEMPTS = 5;\n\nfunction canAttemptVerification(\n  attempts: number\n): boolean {\n  return attempts &lt; MAX_ATTEMPTS;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \ucf54\ub4dc\ub294 \uc81c\ud55c \uc5ec\ubd80\ub97c \ud310\ub2e8\ud558\ub294 \uae30\ubcf8 \ub85c\uc9c1\uc774\ub2e4. \uc2e4\uc81c \uc11c\ubc84\uc5d0\uc11c\ub294 \uc5ec\ub7ec \uc694\uccad\uc774 \ub3d9\uc2dc\uc5d0 \ub4e4\uc5b4\uc640\ub3c4 \ud69f\uc218 \uc81c\ud55c\uc744 \uc6b0\ud68c\ud560 \uc218 \uc5c6\ub3c4\ub85d \uc800\uc7a5\uc18c\uc5d0\uc11c \uc6d0\uc790\uc801\uc73c\ub85c \ud69f\uc218\ub97c \ud655\uc778\ud558\uace0 \uc99d\uac00\uc2dc\ucf1c\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc2e4\ud328 \ud69f\uc218\ub294 \uc778\uc99d \ucf54\ub4dc\uac00 \uc7ac\ubc1c\uae09\ub418\uc5c8\ub2e4\ub294 \uc774\uc720\ub9cc\uc73c\ub85c \ubb34\uc81c\ud55c \ucd08\uae30\ud654\ub418\uc5b4\uc11c\ub294 \uc548 \ub41c\ub2e4. \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \uacf5\uaca9\uc790\uac00 \ucf54\ub4dc\ub97c \uacc4\uc18d \uc7ac\ubc1c\uae09\ubc1b\uc544 \uc2dc\ub3c4 \uc81c\ud55c\uc744 \uc6b0\ud68c\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Rate Limiting\uacfc Brute-force \ubc29\uc5b4<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \uac80\uc99d API\uc5d0\ub294 \uc694\uccad \uc18d\ub3c4 \uc81c\ud55c\uc744 \uc801\uc6a9\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \ub2e4\uc74c\uacfc \uac19\uc740 API\uac00 \uc788\ub2e4\uace0 \uac00\uc815\ud558\uc790.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST \/auth\/2fa\/verify\nContent-Type: application\/json\n\n{\n  \"challengeId\": \"challenge-123\",\n  \"code\": \"042817\"\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc11c\ubc84\ub294 \uc778\uc99d \ucf54\ub4dc\uc758 \uc815\ud569\uc131\uc744 \ud655\uc778\ud558\ub294 \ub3d9\uc2dc\uc5d0 \ub2e4\uc74c \uc0ac\ud56d\uc744 \uac80\uc0ac\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud574\ub2f9 \ucc4c\ub9b0\uc9c0\uac00 \uc874\uc7ac\ud558\ub294\uac00?<\/li>\n\n\n\n<li>\ucc4c\ub9b0\uc9c0\uac00 \ub9cc\ub8cc\ub418\uc9c0 \uc54a\uc558\ub294\uac00?<\/li>\n\n\n\n<li>\uc774\ubbf8 \uc644\ub8cc\ub418\uac70\ub098 \ud3d0\uae30\ub41c \uc778\uc99d \uc808\ucc28\uac00 \uc544\ub2cc\uac00?<\/li>\n\n\n\n<li>\uc0ac\uc6a9\uc790\uac00 \ud5c8\uc6a9\ub41c \uc2dc\ub3c4 \ud69f\uc218\ub97c \ucd08\uacfc\ud588\ub294\uac00?<\/li>\n\n\n\n<li>\uacc4\uc815 \ubc0f IP\ubcc4 \uc694\uccad \uc81c\ud55c\uc744 \ucd08\uacfc\ud588\ub294\uac00?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">IP \uc8fc\uc18c\ub9cc\uc73c\ub85c \uc81c\ud55c\ud558\uba74 \uacf5\uaca9\uc790\uac00 IP\ub97c \ubcc0\uacbd\ud558\uc5ec \uc6b0\ud68c\ud560 \uc218 \uc788\ub2e4. \ubc18\ub300\ub85c \uacc4\uc815\ub9cc\uc73c\ub85c \uc81c\ud55c\ud558\uba74 \uacf5\uaca9\uc790\uac00 \ud2b9\uc815 \uc0ac\uc6a9\uc790\uc758 \uacc4\uc815\uc744 \ubc18\ubcf5\uc801\uc73c\ub85c \uacf5\uaca9\ud558\uc5ec \uc815\uc0c1 \uc0ac\uc6a9\uc790\uc758 \ub85c\uadf8\uc778\uc744 \ubc29\ud574\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub530\ub77c\uc11c IP, \uacc4\uc815, \uc778\uc99d \ucc4c\ub9b0\uc9c0 \ub4f1 \uc5ec\ub7ec \uae30\uc900\uc744 \ud568\uaed8 \uc801\uc6a9\ud558\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub610\ud55c \ud504\ub85d\uc2dc\ub098 \ub85c\ub4dc\ubc38\ub7f0\uc11c \ub4a4\uc5d0\uc11c \uc6b4\uc601\ud55c\ub2e4\uba74 \ud074\ub77c\uc774\uc5b8\ud2b8 IP\ub97c \uc2e0\ub8b0\ud560 \uc218 \uc788\ub294 \ud504\ub85d\uc2dc \uc124\uc815\uc744 \ud1b5\ud574 \uc815\ud655\ud558\uac8c \ud310\ubcc4\ud574\uc57c \ud55c\ub2e4. \uc784\uc758\uc758 <code>X-Forwarded-For<\/code> \ud5e4\ub354\ub97c \uadf8\ub300\ub85c \uc2e0\ub8b0\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc \uc7ac\ubc1c\uae09 \uc81c\ud55c<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \ubc1c\uae09 API\ub3c4 \uacf5\uaca9 \ub300\uc0c1\uc774\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uacf5\uaca9\uc790\uac00 \ud2b9\uc815 \uc774\uba54\uc77c \uc8fc\uc18c\ub85c \uc778\uc99d \ucf54\ub4dc\ub97c \ubc18\ubcf5 \ubc1c\uc1a1\ud558\uba74 \ubb38\uc790 \ubc1c\uc1a1 \ube44\uc6a9\uc774 \uc99d\uac00\ud558\uac70\ub098 \uc0ac\uc6a9\uc790\uc5d0\uac8c \ubd88\ud544\uc694\ud55c \uba54\uc2dc\uc9c0\uac00 \ub300\ub7c9\uc73c\ub85c \uc804\uc1a1\ub420 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774\ub97c \ubc29\uc9c0\ud558\ub824\uba74 \ub2e4\uc74c \uc815\ucc45\uc744 \uc801\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ucf54\ub4dc \uc7ac\ubc1c\uae09 \uc0ac\uc774\uc5d0 \uc77c\uc815\ud55c \ub300\uae30 \uc2dc\uac04 \uc124\uc815<\/li>\n\n\n\n<li>\uc0ac\uc6a9\uc790 \ubc0f IP\ubcc4 \uc2dc\uac04\ub2f9 \ubc1c\uae09 \ud69f\uc218 \uc81c\ud55c<\/li>\n\n\n\n<li>\uae30\uc874 \ucf54\ub4dc \uc7ac\ubc1c\uae09 \uc2dc \uc774\uc804 \ucf54\ub4dc \ubb34\ud6a8\ud654<\/li>\n\n\n\n<li>\uc758\uc2ec\uc2a4\ub7ec\uc6b4 \ubc1c\uae09 \uc694\uccad\uc5d0 \ub300\ud55c \ucd94\uac00 \uac80\uc99d<\/li>\n\n\n\n<li>\uc774\uba54\uc77c \ubc0f SMS \ubc1c\uc1a1 \ube44\uc6a9 \ubaa8\ub2c8\ud130\ub9c1<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ud2b9\ud788 \ucf54\ub4dc \uc7ac\ubc1c\uae09 \uc2dc \uc774\uc804 \ucf54\ub4dc\ub97c \ubb34\ud6a8\ud654\ud574\uc57c \uc5ec\ub7ec \ucf54\ub4dc\uac00 \ub3d9\uc2dc\uc5d0 \uc720\ud6a8\ud55c \uc0c1\ud0dc\uac00 \ub418\ub294 \ubb38\uc81c\ub97c \uc904\uc77c \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\uacc4\uc815 \ud0c8\ucde8 \ud0d0\uc9c0 \ubc0f \ub300\uc751<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uacc4\uc815 \ud0c8\ucde8\ub780?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uacc4\uc815 \ud0c8\ucde8(Account Takeover, ATO)\ub294 \uacf5\uaca9\uc790\uac00 \uc815\uc0c1 \uc0ac\uc6a9\uc790\uc758 \uc778\uc99d \uc815\ubcf4\ub97c \ud68d\ub4dd\ud558\uac70\ub098 \uc778\uc99d \uc808\ucc28\ub97c \uc6b0\ud68c\ud558\uc5ec \uacc4\uc815\uc5d0 \uc811\uadfc\ud558\ub294 \uc0c1\ud669\uc774\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc8fc\uc694 \uc6d0\uc778\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\uc720\ucd9c\ub41c \ube44\ubc00\ubc88\ud638\uc758 \uc7ac\uc0ac\uc6a9<\/li>\n\n\n\n<li>\ud53c\uc2f1 \uc0ac\uc774\ud2b8\ub97c \ud1b5\ud55c \uc778\uc99d \uc815\ubcf4 \ud0c8\ucde8<\/li>\n\n\n\n<li>\uc778\uc99d \ucf54\ub4dc \ubb34\ucc28\ubcc4 \ub300\uc785 \uacf5\uaca9<\/li>\n\n\n\n<li>\uc138\uc158 \ucfe0\ud0a4 \ub610\ub294 \ud1a0\ud070 \ud0c8\ucde8<\/li>\n\n\n\n<li>\uc774\uba54\uc77c \uacc4\uc815 \ud0c8\ucde8<\/li>\n\n\n\n<li>\ube44\ubc00\ubc88\ud638 \uc7ac\uc124\uc815 \uc808\ucc28\uc758 \ucde8\uc57d\uc810<\/li>\n\n\n\n<li>\uc0ac\ud68c\uacf5\ud559\uc801 \uacf5\uaca9\uc744 \ud1b5\ud55c \uc778\uc99d \uc218\ub2e8 \ubcc0\uacbd<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uacc4\uc815 \ud0c8\ucde8 \ub300\uc751\uc740 \ub85c\uadf8\uc778 \uc131\uacf5 \uc5ec\ubd80\ub9cc \ud655\uc778\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \ud574\uacb0\ud560 \uc218 \uc5c6\ub2e4. \uc778\uc99d \uacfc\uc815, \uc138\uc158 \uad00\ub9ac, \uacc4\uc815 \uc124\uc815 \ubcc0\uacbd, \ube44\ubc00\ubc88\ud638 \uc7ac\uc124\uc815 \ub4f1 \uacc4\uc815\uc758 \uc911\uc694\ud55c \uc791\uc5c5\uc744 \uc885\ud569\uc801\uc73c\ub85c \ubcf4\ud638\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc758\uc2ec\uc2a4\ub7ec\uc6b4 \ub85c\uadf8\uc778 \ud0d0\uc9c0<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc11c\ubc84\ub294 \ub85c\uadf8\uc778 \ubc0f \uc778\uc99d \uc774\ubca4\ud2b8\ub97c \uae30\ub85d\ud558\uace0 \ube44\uc815\uc0c1\uc801\uc778 \ud328\ud134\uc744 \ud0d0\uc9c0\ud560 \uc218 \uc788\uc5b4\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \ub2e4\uc74c \uc0c1\ud669\uc740 \ucd94\uac00 \uac80\uc99d\uc774 \ud544\uc694\ud55c \uc2e0\ud638\uac00 \ub420 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\uc9e7\uc740 \uc2dc\uac04 \ub3d9\uc548 \ub85c\uadf8\uc778\uc5d0 \ubc18\ubcf5\uc801\uc73c\ub85c \uc2e4\ud328\ud568<\/li>\n\n\n\n<li>\uc0c8\ub85c\uc6b4 \uae30\uae30\uc5d0\uc11c \ub85c\uadf8\uc778\ud568<\/li>\n\n\n\n<li>\ud3c9\uc18c\uc640 \ub2e4\ub978 \uc704\uce58\ub098 \ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \uc811\uadfc\ud568<\/li>\n\n\n\n<li>\uc5ec\ub7ec \uacc4\uc815\uc5d0 \ub300\ud574 \ub3d9\uc77c\ud55c IP\uc5d0\uc11c \ub85c\uadf8\uc778 \uc2dc\ub3c4\uac00 \ubc1c\uc0dd\ud568<\/li>\n\n\n\n<li>\uc778\uc99d \uc218\ub2e8 \ubcc0\uacbd \uc9c1\ud6c4 \ubbfc\uac10\ud55c \uc791\uc5c5\uc774 \uc218\ud589\ub428<\/li>\n\n\n\n<li>\uc9e7\uc740 \uc2dc\uac04\uc5d0 \uc5ec\ub7ec \uc138\uc158\uc774 \uc0dd\uc131\ub428<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ub2e4\ub9cc \uc0c8\ub85c\uc6b4 IP\ub098 \uae30\uae30\uc5d0\uc11c \ub85c\uadf8\uc778\ud588\ub2e4\ub294 \uc0ac\uc2e4\ub9cc\uc73c\ub85c \uacc4\uc815 \ud0c8\ucde8\ub77c\uace0 \ub2e8\uc815\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4. \ubaa8\ubc14\uc77c \ub124\ud2b8\uc6cc\ud06c\ub098 VPN \uc0ac\uc6a9\uc73c\ub85c\ub3c4 IP \uc8fc\uc18c\uac00 \ub2ec\ub77c\uc9c8 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub530\ub77c\uc11c \uc5ec\ub7ec \uc2e0\ud638\ub97c \uc870\ud569\ud558\uc5ec \uc704\ud5d8\ub3c4\ub97c \ud3c9\uac00\ud558\uace0, \uc704\ud5d8 \uc218\uc900\uc5d0 \ub530\ub77c \ucd94\uac00 \uc778\uc99d\uc744 \uc694\uad6c\ud558\ub294 \ubc29\uc2dd\uc774 \uc801\uc808\ud558\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc704\ud5d8 \uae30\ubc18 \uc778\uc99d<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ubaa8\ub4e0 \ub85c\uadf8\uc778 \uc694\uccad\uc5d0 \ub3d9\uc77c\ud55c \uc778\uc99d \uc808\ucc28\ub97c \uc801\uc6a9\ud558\ub294 \ub300\uc2e0, \uc704\ud5d8\ub3c4\uc5d0 \ub530\ub77c \uc778\uc99d \uc218\uc900\uc744 \uc870\uc808\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\ub85c\uadf8\uc778 \uc694\uccad\n    |\n    v\n\uae30\ubcf8 \uc778\uc99d \uc815\ubcf4 \uac80\uc99d\n    |\n    v\n\uc704\ud5d8 \uc2e0\ud638 \ubd84\uc11d\n    |\n    +-- \ub0ae\uc740 \uc704\ud5d8 --&gt; \uc815\uc0c1 \uc778\uc99d \uc808\ucc28 \uc9c4\ud589\n    |\n    +-- \uc911\uac04 \uc704\ud5d8 --&gt; \ucd94\uac00 \uc778\uc99d \uc694\uad6c\n    |\n    +-- \ub192\uc740 \uc704\ud5d8 --&gt; \ub85c\uadf8\uc778 \ucc28\ub2e8 \ub610\ub294 \uacc4\uc815 \ubcf4\ud638 \uc808\ucc28<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \ubc29\uc2dd\uc740 \uc0ac\uc6a9\uc790 \ud3b8\uc758\uc131\uacfc \ubcf4\uc548 \uc218\uc900 \uc0ac\uc774\uc758 \uade0\ud615\uc744 \ub9de\ucd94\ub294 \ub370 \uc720\uc6a9\ud558\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub2e8, \uacf5\uaca9\uc790\uac00 \uc704\ud5d8\ub3c4 \ud310\ub2e8 \uae30\uc900\uc744 \uc27d\uac8c \ud30c\uc545\ud558\uc5ec \uc6b0\ud68c\ud558\uc9c0 \ubabb\ud558\ub3c4\ub85d \uc138\ubd80 \uaddc\uce59\uacfc \uc784\uacc4\uac12\uc744 \uacf5\uac1c\uc801\uc73c\ub85c \ub178\ucd9c\ud558\uc9c0 \uc54a\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uacc4\uc815 \ud0c8\ucde8 \ubc1c\uc0dd \uc2dc \ub300\uc751<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uacc4\uc815 \ud0c8\ucde8\uac00 \uc758\uc2ec\ub418\uac70\ub098 \ud655\uc778\ub418\uc5c8\ub2e4\uba74 \ucd94\uac00 \ud53c\ud574\ub97c \ub9c9\ub294 \uc870\uce58\uac00 \ud544\uc694\ud558\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ud65c\uc131 \uc138\uc158 \ud3d0\uae30<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uacf5\uaca9\uc790\uac00 \uc774\ubbf8 \ubc1c\uae09\ubc1b\uc740 Access Token\uc774\ub098 \uc138\uc158 \ucfe0\ud0a4\ub97c \uc0ac\uc6a9\ud558\uace0 \uc788\uc744 \uc218 \uc788\ub2e4. \ube44\ubc00\ubc88\ud638\ub9cc \ubcc0\uacbd\ud574\ub3c4 \uae30\uc874 \uc138\uc158\uc774 \uc790\ub3d9\uc73c\ub85c \ubb34\ud6a8\ud654\ub418\ub294 \uac83\uc740 \uc544\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc11c\ubc84 \uce21 \uc138\uc158\uc744 \ud3d0\uae30\ud558\uac70\ub098 \ud1a0\ud070\uc758 \ubb34\ud6a8\ud654 \uc815\ucc45\uc744 \uc801\uc6a9\ud574\uc57c \ud55c\ub2e4. \uc790\uccb4 \ud3ec\ud568\ud615 JWT\ub97c \uc0ac\uc6a9\ud558\ub294 \uacbd\uc6b0\uc5d0\ub294 \ud1a0\ud070 \ub9cc\ub8cc, \uc138\uc158 \ubc84\uc804, \ud3d0\uae30 \ubaa9\ub85d \ub4f1 \uc11c\ube44\uc2a4 \uad6c\uc870\uc5d0 \ub9de\ub294 \ub300\uc751 \ubc29\uc2dd\uc744 \uc124\uacc4\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Refresh Token \ud3d0\uae30<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Refresh Token\uc744 \ud0c8\ucde8\ub2f9\ud588\ub2e4\uba74 \uacf5\uaca9\uc790\uac00 \uc0c8\ub85c\uc6b4 Access Token\uc744 \ubc1c\uae09\ubc1b\uc744 \uc218 \uc788\ub2e4. \ub530\ub77c\uc11c \uc758\uc2ec\uc2a4\ub7ec\uc6b4 \uc138\uc158\uc5d0 \uc5f0\uacb0\ub41c Refresh Token\uc744 \ud3d0\uae30\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Refresh Token Rotation\uc744 \uc801\uc6a9\ud558\ub294 \uc2dc\uc2a4\ud15c\uc774\ub77c\uba74 \uc774\ubbf8 \uc0ac\uc6a9\ud55c Refresh Token\uc774 \ub2e4\uc2dc \uc81c\ucd9c\ub418\ub294 \uc0c1\ud669\uc744 \ud0d0\uc9c0\ud558\uace0, \ud574\ub2f9 \ud1a0\ud070 \uacc4\uc5f4\uc744 \ud3d0\uae30\ud558\ub294 \uc815\ucc45\uc744 \uace0\ub824\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\ube44\ubc00\ubc88\ud638 \uc7ac\uc124\uc815<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc0ac\uc6a9\uc790\uc5d0\uac8c \uc548\uc804\ud55c \ube44\ubc00\ubc88\ud638 \uc7ac\uc124\uc815 \uc808\ucc28\ub97c \uc81c\uacf5\ud55c\ub2e4. \uc7ac\uc124\uc815 \ub9c1\ud06c\ub098 \ud1a0\ud070\uc5d0\ub294 \ucda9\ubd84\ud55c \ubb34\uc791\uc704\uc131, \ub9cc\ub8cc \uc2dc\uac04, \uc77c\ud68c\uc131 \uc0ac\uc6a9 \uc815\ucc45\uc744 \uc801\uc6a9\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\uc778\uc99d \uc218\ub2e8 \ubcf5\uad6c<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uacf5\uaca9\uc790\uac00 \uc774\uba54\uc77c \uc8fc\uc18c, \ud734\ub300\uc804\ud654 \ubc88\ud638, \uc778\uc99d \uc571 \ub4f1\uc744 \ubcc0\uacbd\ud588\ub2e4\uba74 \uc815\ub2f9\ud55c \uc0ac\uc6a9\uc790\uac00 \uacc4\uc815\uc744 \ubcf5\uad6c\ud560 \uc218 \uc788\ub294 \uc808\ucc28\uac00 \ud544\uc694\ud558\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ubcf5\uad6c \uacfc\uc815\uc740 \uacf5\uaca9\uc790\uac00 \ud0c8\ucde8\ud55c \uacc4\uc815\ub9cc\uc73c\ub85c \uc0c8\ub85c\uc6b4 \uc778\uc99d \uc218\ub2e8\uc744 \ub4f1\ub85d\ud560 \uc218 \uc5c6\ub3c4\ub85d \uc124\uacc4\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\uc0ac\uc6a9\uc790 \uc54c\ub9bc<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc0c8\ub85c\uc6b4 \uae30\uae30 \ub85c\uadf8\uc778, \ube44\ubc00\ubc88\ud638 \ubcc0\uacbd, \uc774\uba54\uc77c \ubcc0\uacbd, \uc778\uc99d \uc218\ub2e8 \ubcc0\uacbd, \ubaa8\ub4e0 \uc138\uc158 \ub85c\uadf8\uc544\uc6c3 \ub4f1\uc758 \uc911\uc694\ud55c \uc774\ubca4\ud2b8\uac00 \ubc1c\uc0dd\ud558\uba74 \uc0ac\uc6a9\uc790\uc5d0\uac8c \uc54c\ub9bc\uc744 \uc81c\uacf5\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc54c\ub9bc\uc5d0\ub294 \uc0ac\uc6a9\uc790\uac00 \uc9c1\uc811 \uc218\ud589\ud558\uc9c0 \uc54a\uc740 \uc791\uc5c5\uc744 \uc2e0\uace0\ud558\uac70\ub098 \uacc4\uc815\uc744 \ubcf4\ud638\ud560 \uc218 \uc788\ub294 \ubc29\ubc95\ub3c4 \ud3ec\ud568\ud558\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ubbfc\uac10\ud55c \uc791\uc5c5\uc5d0\ub294 \uc7ac\uc778\uc99d \uc801\uc6a9<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ub85c\uadf8\uc778\ud560 \ub54c \uc778\uc99d\uc744 \ud55c \ubc88 \uc644\ub8cc\ud588\ub2e4\uace0 \ud574\uc11c \ubaa8\ub4e0 \uc791\uc5c5\uc744 \ubb34\uc870\uac74 \ud5c8\uc6a9\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub2e4\uc74c\uacfc \uac19\uc740 \uc791\uc5c5\uc5d0\ub294 \ube44\ubc00\ubc88\ud638 \uc7ac\uc785\ub825\uc774\ub098 \ucd94\uac00 \uc778\uc99d\uc744 \uc694\uad6c\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ube44\ubc00\ubc88\ud638 \ubcc0\uacbd<\/li>\n\n\n\n<li>\uc774\uba54\uc77c \uc8fc\uc18c \ubcc0\uacbd<\/li>\n\n\n\n<li>\ud734\ub300\uc804\ud654 \ubc88\ud638 \ubcc0\uacbd<\/li>\n\n\n\n<li>2FA \ud65c\uc131\ud654 \ubc0f \ube44\ud65c\uc131\ud654<\/li>\n\n\n\n<li>\uacb0\uc81c \uc218\ub2e8 \ubcc0\uacbd<\/li>\n\n\n\n<li>\uc911\uc694\ud55c \uac1c\uc778\uc815\ubcf4 \ubcc0\uacbd<\/li>\n\n\n\n<li>\uacc4\uc815 \uc0ad\uc81c<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774\ub7ec\ud55c \uc791\uc5c5\uc740 \uacc4\uc815 \ud0c8\ucde8 \uc774\ud6c4 \uacf5\uaca9\uc790\uac00 \uacc4\uc815 \uc18c\uc720\uad8c\uc744 \uc601\uad6c\uc801\uc73c\ub85c \ud655\ubcf4\ud558\ub294 \uac83\uc744 \uc5b4\ub835\uac8c \ub9cc\ub4e0\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Node.js\uc640 Redis\ub97c \ud65c\uc6a9\ud55c \uc778\uc99d \ucf54\ub4dc \uad00\ub9ac \uc608\uc2dc<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\ub2e4\uc74c\uc740 Redis\ub97c \uc0ac\uc6a9\ud574 \uc778\uc99d \ucf54\ub4dc\uc758 \uc800\uc7a5\uacfc \ub9cc\ub8cc\ub97c \uad00\ub9ac\ud558\ub294 \uae30\ubcf8\uc801\uc778 \uad6c\uc870\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc2e4\uc81c \uc6b4\uc601 \ucf54\ub4dc\uc5d0\uc11c\ub294 \uc778\uc99d \ucf54\ub4dc\uc758 \uc548\uc804\ud55c \ubc1c\uae09\uacfc \uc804\ub2ec, \uacc4\uc815\ubcc4 \uc2dc\ub3c4 \uc81c\ud55c, \uc6d0\uc790\uc801 \uac80\uc99d, \uc778\uc99d \uc644\ub8cc \ucc98\ub9ac\uae4c\uc9c0 \ud568\uaed8 \uad6c\ud604\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc \uc800\uc7a5<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import { randomInt, createHmac } from \"node:crypto\";\nimport type { RedisClientType } from \"redis\";\n\nconst CODE_TTL_SECONDS = 300;\n\nfunction generateCode(): string {\n  return randomInt(0, 1_000_000)\n    .toString()\n    .padStart(6, \"0\");\n}\n\nfunction createCodeDigest(\n  userId: string,\n  code: string,\n  secret: string\n): string {\n  return createHmac(\"sha256\", secret)\n    .update(`${userId}:${code}`)\n    .digest(\"hex\");\n}\n\nasync function issueVerificationCode(\n  redis: RedisClientType,\n  userId: string,\n  secret: string\n): Promise&lt;string&gt; {\n  const code = generateCode();\n  const digest = createCodeDigest(userId, code, secret);\n\n  const key = `auth:2fa:${userId}`;\n\n  await redis.set(\n    key,\n    JSON.stringify({\n      digest,\n      attempts: 0,\n    }),\n    {\n      EX: CODE_TTL_SECONDS,\n    }\n  );\n\n  return code;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \uc608\uc2dc\ub294 \uc778\uc99d \ucf54\ub4dc\uc758 \uac80\uc99d\uac12\uc744 Redis\uc5d0 \uc800\uc7a5\ud558\uace0 5\ubd84\uc758 TTL\uc744 \uc124\uc815\ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>secret<\/code>\uc740 \ud658\uacbd\ubcc0\uc218\ub098 \ube44\ubc00 \uad00\ub9ac \uc2dc\uc2a4\ud15c\uc5d0\uc11c \uac00\uc838\uc640\uc57c \ud558\uba70, \uc778\uc99d \ucf54\ub4dc\uc640 \ud568\uaed8 \uc800\uc7a5\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4. \ub610\ud55c <code>userId<\/code>\ub97c \uadf8\ub300\ub85c \ud0a4\ub85c \uc0ac\uc6a9\ud558\ub294 \ubc29\uc2dd\uc740 \uae30\ubcf8\uc801\uc778 \uc608\uc2dc\ub2e4. \uc2e4\uc81c \uc2dc\uc2a4\ud15c\uc5d0\uc11c\ub294 \ub3d9\uc2dc \ub85c\uadf8\uc778, \uc5ec\ub7ec \uae30\uae30, \uc7ac\ubc1c\uae09, \uc0ac\uc6a9\uc790\ubcc4 \uc2dc\ub3c4 \uc81c\ud55c \ub4f1\uc744 \uace0\ub824\ud574 \uc778\uc99d \ucc4c\ub9b0\uc9c0 ID\ub97c \ubcc4\ub3c4\ub85c \uc0ac\uc6a9\ud558\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \ucf54\ub4dc \ubc1c\uae09 \ud568\uc218\ub294 \ucf54\ub4dc\ub97c \ubc18\ud658\ud558\uc9c0\ub9cc, \uc2e4\uc81c \uc11c\ube44\uc2a4\uc5d0\uc11c\ub294 \ubc18\ud658\uac12\uc744 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0 \uc9c1\uc811 \ub178\ucd9c\ud558\uc9c0 \uc54a\uc544\uc57c \ud55c\ub2e4. \uac80\uc99d \ucf54\ub4dc\ub294 \uc2e0\ub8b0\ud560 \uc218 \uc788\ub294 \uc774\uba54\uc77c \ub610\ub294 SMS \uc804\ub2ec \uc2dc\uc2a4\ud15c\uc744 \ud1b5\ud574 \uc0ac\uc6a9\uc790\uc5d0\uac8c \uc804\ub2ec\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ucf54\ub4dc \uac80\uc99d<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import { timingSafeEqual } from \"node:crypto\";\n\nconst MAX_ATTEMPTS = 5;\n\nfunction safeDigestEqual(\n  expected: string,\n  actual: string\n): boolean {\n  const a = Buffer.from(expected, \"hex\");\n  const b = Buffer.from(actual, \"hex\");\n\n  return (\n    a.length === b.length &amp;&amp;\n    timingSafeEqual(a, b)\n  );\n}\n\nasync function verifyCode(\n  redis: RedisClientType,\n  userId: string,\n  inputCode: string,\n  secret: string\n): Promise&lt;boolean&gt; {\n  if (!\/^\\d{6}$\/.test(inputCode)) {\n    return false;\n  }\n\n  const key = `auth:2fa:${userId}`;\n  const value = await redis.get(key);\n\n  if (!value) {\n    return false;\n  }\n\n  const record = JSON.parse(value) as {\n    digest: string;\n    attempts: number;\n  };\n\n  if (record.attempts &gt;= MAX_ATTEMPTS) {\n    await redis.del(key);\n    return false;\n  }\n\n  const actualDigest = createCodeDigest(\n    userId,\n    inputCode,\n    secret\n  );\n\n  if (\n    !safeDigestEqual(\n      record.digest,\n      actualDigest\n    )\n  ) {\n    record.attempts += 1;\n\n    if (record.attempts &gt;= MAX_ATTEMPTS) {\n      await redis.del(key);\n    } else {\n      const ttl = await redis.ttl(key);\n\n      if (ttl &gt; 0) {\n        await redis.set(\n          key,\n          JSON.stringify(record),\n          { EX: ttl }\n        );\n      }\n    }\n\n    return false;\n  }\n\n  await redis.del(key);\n\n  return true;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uc704 \ucf54\ub4dc\ub294 \ud750\ub984\uc744 \uc774\ud574\ud558\uae30 \uc704\ud55c \uc608\uc2dc\ub2e4. <strong>\uc774 \uad6c\ud604\uc744 \uadf8\ub300\ub85c \uc6b4\uc601 \ud658\uacbd\uc5d0 \uc801\uc6a9\ud574\uc11c\ub294 \uc548 \ub41c\ub2e4.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud2b9\ud788 \ub2e4\uc74c\uacfc \uac19\uc740 \ubcf4\uc644\uc774 \ud544\uc694\ud558\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Redis\uc758 \uc870\ud68c, \uc2dc\ub3c4 \ud69f\uc218 \uc99d\uac00, \uac80\uc99d, \uc0ad\uc81c\uac00 \uc5ec\ub7ec \uc694\uccad\uc5d0\uc11c \uc6d0\uc790\uc801\uc73c\ub85c \ucc98\ub9ac\ub418\ub3c4\ub85d Lua \uc2a4\ud06c\ub9bd\ud2b8\ub098 \uc801\uc808\ud55c \ud2b8\ub79c\uc7ad\uc158\uc744 \uc0ac\uc6a9\ud55c\ub2e4.<\/li>\n\n\n\n<li>\uc798\ubabb\ub41c \ucf54\ub4dc\ub97c \ub3d9\uc2dc\uc5d0 \uc81c\ucd9c\ud574\ub3c4 \ud5c8\uc6a9 \ud69f\uc218\ub97c \ucd08\uacfc\ud560 \uc218 \uc5c6\ub3c4\ub85d \ud55c\ub2e4.<\/li>\n\n\n\n<li>\uc778\uc99d \ucf54\ub4dc \uac80\uc99d \uc131\uacf5\uacfc \ucd5c\uc885 \ub85c\uadf8\uc778 \uad8c\ud55c \ubc1c\uae09 \uc0ac\uc774\uc758 \uc0c1\ud0dc \uc804\uc774\ub97c \uc548\uc804\ud558\uac8c \ucc98\ub9ac\ud55c\ub2e4.<\/li>\n\n\n\n<li>\uc0ac\uc6a9\uc790\ubcc4 \ubc0f IP\ubcc4 \uc694\uccad \uc81c\ud55c\uc744 \ubcc4\ub3c4\ub85c \uc801\uc6a9\ud55c\ub2e4.<\/li>\n\n\n\n<li>\ub9cc\ub8cc\ub41c \ucf54\ub4dc, \uc7ac\ubc1c\uae09\ub41c \ucf54\ub4dc, \uc774\ubbf8 \uc0ac\uc6a9\ub41c \ucf54\ub4dc\uac00 \ub2e4\uc2dc \uc2b9\uc778\ub418\uc9c0 \uc54a\ub3c4\ub85d \ud55c\ub2e4.<\/li>\n\n\n\n<li>\uc778\uc99d \ucf54\ub4dc\uc640 \uc778\uc99d \ud1a0\ud070\uc744 \ub85c\uadf8\uc5d0 \uae30\ub85d\ud558\uc9c0 \uc54a\ub294\ub2e4.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ub610\ud55c \uc704 \uc608\uc2dc\uc5d0\uc11c\ub294 \uc131\uacf5\ud55c \uc778\uc99d \ucf54\ub4dc\uc758 \ub808\ucf54\ub4dc\ub97c \uc0ad\uc81c\ud558\uc9c0\ub9cc, \uc778\uc99d \uc644\ub8cc \uc0c1\ud0dc\ub97c \ubcc4\ub3c4\uc758 \uc11c\ubc84 \uce21 \ucc4c\ub9b0\uc9c0 \uc0c1\ud0dc\ub85c \uad00\ub9ac\ud558\ub294 \uc124\uacc4\ub3c4 \uac00\ub2a5\ud558\ub2e4. \ud575\uc2ec\uc740 \uc131\uacf5 \ucc98\ub9ac\uac00 \uc6d0\uc790\uc801\uc73c\ub85c \uc774\ub8e8\uc5b4\uc9c0\uace0, \uac19\uc740 \ucf54\ub4dc\ub97c \uc774\uc6a9\ud574 \ub450 \ubc88 \uc778\uc99d\uc744 \uc644\ub8cc\ud560 \uc218 \uc5c6\uc5b4\uc57c \ud55c\ub2e4\ub294 \uc810\uc774\ub2e4.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\uc6b4\uc601 \ud658\uacbd\uc5d0\uc11c \ucd94\uac00\ub85c \uace0\ub824\ud560 \uc0ac\ud56d<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \uc0c1\ud0dc\ub97c \uba85\ud655\ud788 \ubd84\ub9ac\ud558\uae30<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \uc2dc\uc2a4\ud15c\uc5d0\ub294 \uc11c\ub85c \ub2e4\ub978 \uc0c1\ud0dc\uac00 \uc874\uc7ac\ud55c\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ubbf8\uc778\uc99d<\/li>\n\n\n\n<li>\ube44\ubc00\ubc88\ud638 \uc778\uc99d \uc644\ub8cc<\/li>\n\n\n\n<li>\ucd94\uac00 \uc778\uc99d \ub300\uae30<\/li>\n\n\n\n<li>\ucd94\uac00 \uc778\uc99d \uc644\ub8cc<\/li>\n\n\n\n<li>\uc778\uc99d \uc2e4\ud328 \ub610\ub294 \uc7a0\uae08<\/li>\n\n\n\n<li>\uc778\uc99d \ub9cc\ub8cc \ub610\ub294 \ud3d0\uae30<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774 \uc0c1\ud0dc\ub4e4\uc744 \uba85\ud655\ud558\uac8c \ubd84\ub9ac\ud558\uba74 \ucd94\uac00 \uc778\uc99d\uc774 \uc644\ub8cc\ub418\uc9c0 \uc54a\uc740 \uc0ac\uc6a9\uc790\uac00 \uc77c\ubc18 API\ub97c \ud638\ucd9c\ud558\ub294 \ubb38\uc81c\ub97c \ubc29\uc9c0\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc624\ub958 \uba54\uc2dc\uc9c0\uc640 \ub85c\uadf8 \uad00\ub9ac<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc778\uc99d \uc2e4\ud328 \uc751\ub2f5\uc740 \uacf5\uaca9\uc790\uc5d0\uac8c \ubd88\ud544\uc694\ud55c \uc815\ubcf4\ub97c \uc81c\uacf5\ud558\uc9c0 \uc54a\uc544\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc608\ub97c \ub4e4\uc5b4 \uc0ac\uc6a9\uc790 \uacc4\uc815\uc758 \uc874\uc7ac \uc5ec\ubd80, \uc778\uc99d \ucf54\ub4dc\uc758 \uc77c\ubd80, \ub0b4\ubd80 \uac80\uc99d \uc0c1\ud0dc\ub97c \uacfc\ub3c4\ud558\uac8c \ub178\ucd9c\ud558\uc9c0 \uc54a\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ub85c\uadf8\uc5d0\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \uc774\ubca4\ud2b8\ub97c \uae30\ub85d\ud560 \uc218 \uc788\ub2e4.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\uc778\uc99d \ucf54\ub4dc \ubc1c\uae09<\/li>\n\n\n\n<li>\uc778\uc99d \ucf54\ub4dc \uac80\uc99d \uc131\uacf5 \ubc0f \uc2e4\ud328<\/li>\n\n\n\n<li>\uc778\uc99d \uc2dc\ub3c4 \uc81c\ud55c \ucd08\uacfc<\/li>\n\n\n\n<li>\ucd94\uac00 \uc778\uc99d \uc644\ub8cc<\/li>\n\n\n\n<li>\uc778\uc99d \uc218\ub2e8 \ubcc0\uacbd<\/li>\n\n\n\n<li>\uc138\uc158 \ud3d0\uae30<\/li>\n\n\n\n<li>\uc758\uc2ec\uc2a4\ub7ec\uc6b4 \ub85c\uadf8\uc778 \ud0d0\uc9c0<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\ub85c\uadf8\uc5d0\ub294 \ube44\ubc00\ubc88\ud638, \uc778\uc99d \ucf54\ub4dc, Access Token, Refresh Token, \uc138\uc158 \ucfe0\ud0a4, \ube44\ubc00\ud0a4 \ub4f1\uc758 \ubbfc\uac10\ud55c \uc815\ubcf4\ub97c \ub0a8\uae30\uc9c0 \uc54a\uc544\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\uc778\uc99d \ubcf5\uad6c \uc808\ucc28<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\uc0ac\uc6a9\uc790\uac00 \ud734\ub300\uc804\ud654\ub97c \ubd84\uc2e4\ud558\uac70\ub098 \uc778\uc99d \uc571\uc5d0 \uc811\uadfc\ud560 \uc218 \uc5c6\uac8c \ub418\uc5c8\uc744 \ub54c\ub97c \ub300\ube44\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ubcf5\uad6c \ucf54\ub4dc, \ubcc4\ub3c4\uc758 \uc778\uc99d \uc218\ub2e8, \uac15\ud654\ub41c \ubcf8\uc778 \ud655\uc778 \uc808\ucc28 \ub4f1\uc744 \uc81c\uacf5\ud560 \uc218 \uc788\ub2e4. \ubcf5\uad6c \ucf54\ub4dc\ub294 \uc77c\ubc18 \uc778\uc99d \ucf54\ub4dc\uc640 \ub9c8\ucc2c\uac00\uc9c0\ub85c \ucda9\ubd84\ud788 \ubb34\uc791\uc704\uc801\uc774\uc5b4\uc57c \ud558\uba70, \uc77c\ud68c\uc131 \uc0ac\uc6a9\uacfc \uc548\uc804\ud55c \uc800\uc7a5 \uc815\ucc45\uc744 \uc801\uc6a9\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2FA\ub97c \ube44\ud65c\uc131\ud654\ud558\ub294 \uacfc\uc815 \uc5ed\uc2dc \uc911\uc694\ud55c \ubcf4\uc548 \uc791\uc5c5\uc774\ub2e4. \uc774\ubbf8 \ud0c8\ucde8\ub41c \uc138\uc158\ub9cc\uc73c\ub85c \uc778\uc99d \uc218\ub2e8\uc744 \uc81c\uac70\ud560 \uc218 \uc5c6\ub3c4\ub85d \ucd5c\uadfc \uc778\uc99d \uc5ec\ubd80\uc640 \ucd94\uac00 \ud655\uc778\uc744 \uc694\uad6c\ud574\uc57c \ud55c\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud68c\uc6d0\uac00\uc785\uacfc \ub85c\uadf8\uc778\uc5d0 \uc544\uc774\ub514\uc640 \ube44\ubc00\ubc88\ud638\ub9cc \uc0ac\uc6a9\ud558\ub294 \uc2dc\uc2a4\ud15c\uc740 \ube44\ubc00\ubc88\ud638\uac00 \uc720\ucd9c\ub418\ub294 \uc21c\uac04 \uacc4\uc815\uc774 \ud0c8\ucde8\ub420 \uc218 \uc788\ub2e4. \ube44\ubc00\ubc88\ud638\uac00 \uc548\uc804\ud558\uac8c \ud574\uc2f1\ub418\uc5b4 \uc788\ub354\ub77c\ub3c4 \uc0ac\uc6a9\uc790\uac00 \ud53c\uc2f1 \uc0ac\uc774\ud2b8\uc5d0 \uc785\ub825\ud558\uac70\ub098 \ub2e4\ub978 \uc11c\ube44\uc2a4\uc5d0\uc11c \uc7ac\uc0ac\uc6a9\ud55c \ube44\ubc00\ubc88\ud638\uac00 \uc720\ucd9c\ub418\uba74 \uc778\uc99d \uccb4\uacc4 \uc790\uccb4\uac00 \ubb34\ub825\ud654\ub420 \uc218 \uc788\ub2e4. \uc774\ub97c \ubcf4\uc644\ud558\uae30 \uc704\ud574 \uc0ac\uc6a9\ud558\ub294 \uac83\uc774 \ucd94\uac00 \uc778\uc99d(Multi-Factor Authentication, MFA) \uc774\ub2e4. \ucd94\uac00 \uc778\uc99d\uc740 \ube44\ubc00\ubc88\ud638 \uc678\uc5d0 \ubcc4\ub3c4\uc758 \uc778\uc99d \uc218\ub2e8\uc744 \uc694\uad6c\ud558\uc5ec \uacc4\uc815 \uc811\uadfc\uc5d0 \ud544\uc694\ud55c \ubcf4\uc548 \uc218\uc900\uc744 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2667","post","type-post","status-publish","format-standard","hentry","category-dev-logs"],"_links":{"self":[{"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/posts\/2667","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2667"}],"version-history":[{"count":1,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/posts\/2667\/revisions"}],"predecessor-version":[{"id":2668,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=\/wp\/v2\/posts\/2667\/revisions\/2668"}],"wp:attachment":[{"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2667"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2667"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wayhope.kro.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2667"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}