Computer >> 컴퓨터 >  >> 프로그래밍 >> Redis

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지

데이터 유출은 인터넷에서 중요한 문제입니다. Statista에 따르면 2022년에만 4억 명이 넘는 사람들이 데이터 유출로 인해 영향을 받았습니다. 자신의 데이터가 인터넷 전체에 유출되는 것을 원하는 사람은 아무도 없으므로 사용자 개인정보를 존중하는 보안 애플리케이션을 구축하는 것은 많은 산업에서 매우 중요합니다.

유출을 방지하는 한 가지 방법은 문제가 있는 데이터를 다른 서비스나 사용자에게 전달하기 전에 필터링하는 것입니다. 이 방법을 사용하려면 필터링이 성능에 미치는 영향을 가능한 한 작게 유지하기 위해 데이터가 빠져나가는 것을 방지하고 대기 시간이 짧은 인프라를 보장하는 최신 필터가 필요합니다.

Redis®용 Upstash와 Vercel Edge Functions는 두 가지 요구 사항을 모두 충족하면서 문제를 해결할 수 있는 강력한 팀을 구성합니다. 지연 시간이 짧은 서버리스 솔루션은 모두 사용자 가까이에 배포할 수 있습니다. Vercel의 새로운 크론 기능을 사용하면 필터 데이터가 정기적으로 업데이트되도록 할 수 있습니다.

이러한 필터가 어떻게 작동하는지 설명하기 위해 우리는 이 서버리스 에지 기술을 활용하여 욕설을 필터링하는 프런트엔드와 백엔드를 구축할 것입니다.

기능

앱은 Vercel의 cron 기능을 사용하여 원격 API의 현재 단어로 Redis용 Upstash 데이터베이스를 업데이트합니다.

데이터를 얻는 세 가지 방법이 있습니다:

  1. 필터링된 텍스트가 포함된 웹사이트를 반환합니다.
  2. 데이터 저장소에서 필터링된 텍스트가 포함된 JSON을 반환합니다.
  3. 텍스트를 수락하고 필터링된 텍스트와 함께 JSON을 반환합니다.

기술

Next.js로 앱을 빌드하고 Vercel에 배포하겠습니다. 이렇게 하면 엣지 기능을 사용할 때 원활한 서버리스 개발 경험을 갖게 될 것입니다.

지연 시간이 짧고 사용이 간편하기 때문에 Upstash for Redis®를 데이터 저장소로 사용할 것입니다.

두 서비스 모두 무료 등급으로 제공되며 주문형 가격이 적용됩니다.

전제조건

서비스를 이용하려면 계정이 필요합니다:

  • Vercel이 코드를 다운로드하고 배포할 수 있도록 코드를 업로드하는 GitHub
  • 홈 페이지와 엣지 기능을 갖춘 애플리케이션을 호스팅하는 Vercel
  • 필터링하려는 단어 목록을 저장하는 Upstash

구현

시작하려면 새로운 GitHub 저장소를 만들고 확인하세요. "README 파일 추가"를 선택하여 비어 있지 않도록 합니다. 저장소가 비어 있지 않기 때문에 GitHub를 사용하면 Node.js 및 Git-GitHub 연결로 사전 구성된 Codespace를 시작할 수 있습니다.

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지 그림 1:Codespace 시작

먼저, 새로운 Next.js 프로젝트를 생성하고 다음 명령을 사용하여 Upstash Redis 클라이언트를 설치해야 합니다:

$ npx create-next-app@latest --typescript
$ npm i @upstash/redis

새로고침 기능 구현

우리가 구현할 첫 번째 기능은 나쁜 단어 목록을 새로 고치는 기능입니다. 그렇게 하려면 pages/api/refresh-list.ts에 새 파일을 만드세요. 다음 내용이 포함되어 있습니다:

파일 pages/api/refresh-list.ts :

import { Redis } from "@upstash/redis";
 
export const config = { runtime: "edge" };
 
const redisClient = new Redis({
 url: process.env.UPSTASH_REDIS_URL,
 token: process.env.UPSTASH_REDIS_TOKEN,
});
 
export default async function handler() {
 const wordResponse = await fetch(
 "https://raw.githubusercontent.com/kay-is/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words/master/en",
 );
 const words = await wordResponse.text();
 
 const redisCommands = redisClient.pipeline();
 words
 .trim()
 .split("\n")
 .forEach((word) => redisCommands.sadd("words", word));
 await redisCommands.exec();
}

먼저 엣지에서 실행되도록 기능을 구성합니다. 이 기능은 백그라운드에서 실행되기 때문에 여기서는 이것이 필수적인 것은 아니지만 Vercel Edge Functions는 Cloudflare Workers에 의해 구동되므로 Node.js가 기본적으로 지원하지 않는 가져오기 메서드를 사용할 수 있습니다.

핸들러는 잘못된 단어가 포함된 텍스트 파일을 Upstash Redis에 로드합니다. 파이프라인 기능을 사용하면 모든 Redis 명령에 대해 하나의 요청만 보낼 수 있습니다.

우리는 단어를 저장하기 위해 세트를 사용하므로 중복되지 않습니다. 또한 나중에 하나의 명령으로 모든 단어를 문자열 배열로 로드할 수 있습니다.

개인 데이터를 필터링하려면 계정 데이터베이스를 사용하여 필터의 기초로 사용자의 이메일, 전화번호, 이름 및 주소를 얻을 수 있습니다.

Vercel에게 이 함수를 cron 함수로 지정하려면 프로젝트 루트에 다음 내용이 포함된 vercel.json 파일을 생성해야 합니다.

파일 vercel.json :

{
 "crons": [
 {
 "path": "/api/refresh-list",
 "schedule": "0 10 * * *"
 }
 ]
}

이 구성을 사용하면 Vercel이 매일 10:00 UTC에 목록 새로 고침 기능을 실행하게 됩니다.

무료 Vercel 계정은 하루에 한 번의 자동 실행만 지원합니다. 이 예에서는 충분하지만 데이터가 더 자주 변경되는 경우 업데이트 속도를 높여야 합니다.

필터 유틸리티 구현

다음 기능은 데이터베이스의 단어와 일치하는 텍스트의 단어를 마스킹하는 유틸리티 기능입니다. utils/word-filter.ts에 새 파일을 만들고 다음 코드를 추가하세요.

파일 utils/word-filter.ts :

import { Redis } from "@upstash/redis";
 
const redisClient = new Redis({
 url: process.env.UPSTASH_REDIS_URL,
 token: process.env.UPSTASH_REDIS_TOKEN,
});
 
export async function filter(text: string) {
 const filteredWords = await redisClient.smembers("words");
 
 let maskedText = text;
 for (let word of filteredWords)
 maskedText = maskedText.replaceAll(new RegExp(word, "gi"), "[REDACTED]");
 
 return maskedText;
}

이번에도 함수는 Upstash Redis 클라이언트를 사용하지만 이번에는 이전에 저장한 데이터를 로드합니다.

문자열 배열을 얻었으므로 간단히 반복하여 텍스트의 모든 나쁜 단어를 "[편집됨]"으로 바꾸는 대체 함수를 호출할 수 있습니다.

이 함수는 필터링하는 단어의 유형에 관심이 없습니다. 이 경우에는 "작업하기에 안전하지 않다"라는 단어가 사용되지만 필터 프로세스는 이전에 저장한 데이터에만 의존합니다.

홈페이지 구현

필터가 작동하는 모습을 보려면 pages/index.ts의 내용을 바꾸세요. 다음과 같습니다:

파일 pages/index.ts :

import Head from "next/head";
import { filter } from "@/utils/word-filter";
 
export const config = { runtime: "experimental-edge" };
 
interface HomeProps {
 maskedText: string;
}
 
export default function Home(props: HomeProps) {
 return (
 <>
 <Head>
 <title>Text with Filtered Words</title>
 </Head>
 <div>
 <h1>Text with Filtered Words</h1>
 <p>{props.maskedText}</p>
 </div>
 </>
 );
}
 
export async function getServerSideProps(): Promise<{ props: HomeProps }> {
 const maskedText = await filter(
 "He slipped and fell on his butt. Well, that wasn't very sexy."
 );
 return { props: { maskedText } };
}

이 구성은 서버 측 렌더링을 포함하여 모든 것이 에지에서 실행되도록 보장합니다. 이 Vercel 기능은 아직 실험적입니다.

흥미로운 부분은 getServerSideProps입니다. filter을 사용하는 함수 정적 텍스트에서 이전부터 작동합니다. 서버에서만 호출되므로 필터링되지 않은 데이터는 클라이언트에 도달하지 않습니다.

실제 애플리케이션에서 이 텍스트는 표시되기 전에 정리해야 하는 개인 데이터가 있는 데이터베이스에서 나올 수 있습니다.

첫 번째 API 경로 구현

첫 번째 API 경로는 홈 페이지처럼 작동합니다. JSON은 반환하고 HTML은 반환하지 않습니다. pages/api/filtered-data.ts에 파일을 생성하세요 다음 코드를 사용하세요:

파일 pages/api/filtered-data.ts :

import { filter } from "@/utils/word-filter";
 
export const config = { runtime: "edge" };
 
export default async function handler() {
 const maskedText = await filter(
 "He slipped and fell on his butt. Well, that wasn't very sexy.",
 );
 
 return new Response(JSON.stringify({ text: maskedText }), {
 status: 200,
 headers: { "content-type": "application/json" },
 });
}

다시 말하지만, 런타임은 엣지이며 getServerSideProps 함수와 마찬가지로 정적 텍스트를 사용합니다.

두 번째 API 경로 구현

이 경로는 요청을 통해 텍스트를 받아들이고 필터링된 버전을 반환합니다. pages/api/filter.ts에 새 파일을 만듭니다. 그리고 다음 코드를 추가하세요:

파일 pages/api/filter.ts :

import type { NextApiRequest } from "next";
 
import { filter } from "@/utils/word-filter";
 
export const config = { runtime: "edge" };
 
export default async function handler(request: NextApiRequest) {
 const { text } = await new Response(request.body).json();
 const maskedText = await filter(text);
 return new Response(JSON.stringify({ text: maskedText }), {
 status: 200,
 headers: { "content-type": "application/json" },
 });
}

이번에는 필터링하려는 텍스트를 얻기 위해 본문을 구문 분석해야 합니다. Vercel의 Edge Functions에서는 body ReadableStream입니다; Response로 변환하면 , 기본 JSON 파서를 사용하여 데이터를 추출할 수 있습니다.

요청에서 데이터를 얻은 후에는 모든 것이 이전처럼 작동합니다.

푸시 코드 변경

이제 모든 것이 구현되었으므로 다음 명령을 사용하여 코드를 GitHub 저장소에 푸시해야 합니다.

$ git add -A
$ git commit -m "Init"
$ git push

그 후에는 Vercel에서 코드를 온라인으로 다운로드하여 배포할 수 있습니다.

배포

환경 변수와 Vercel 프로젝트에 대한 자격 증명을 얻으려면 Upstash Redis 데이터베이스를 생성해야 합니다.

Redis 데이터베이스 생성

Upstash 콘솔에서 "데이터베이스 생성" 버튼을 클릭하여 새로운 Redis 데이터베이스를 생성할 수 있습니다. 그림 2는 구성을 보여줍니다. 이 예에서는 지역 데이터베이스이면 충분하지만 전 세계에 분산된 사용자가 있고 지연 시간을 낮게 유지하려는 경우 전역 유형을 선택할 수도 있습니다.

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지

그림 2:새 데이터베이스 만들기

생성 후 REST API 카테고리에서 환경 변수에 필요한 URL과 토큰을 찾을 수 있습니다. 그림 3과 같습니다.

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지

그림 3:데이터베이스 자격 증명

Vercel 프로젝트 생성

새로운 Vercel 프로젝트를 생성하려면 브라우저에서 Vercel 대시보드를 열고 중앙에 있는 "Create a New Project"를 클릭하세요. Vercel을 GitHub 계정과 연결한 후 가져올 저장소를 선택할 수 있습니다.

기본 구성을 유지하고 위에서 Upstash Redis 자격 증명을 사용하여 환경 변수를 추가할 수 있습니다. 그림 4는 참고용으로 Vercel의 생성 UI를 보여줍니다.

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지

그림 4:Vercel 프로젝트 생성

환경 변수의 이름은 UPSTASH_REDIS_URL입니다. 및 UPSTASH_REDIS_TOKEN . 이전 단계의 값을 사용하여 생성합니다.

"배포"를 클릭하면 Vercel이 GitHub 저장소에서 코드를 다운로드하고 배포합니다.

앱 테스트

배포 후에도 cron 작업이 아직 실행되지 않았기 때문에 앱은 필터링되지 않은 단어를 계속 표시합니다. 하지만 첫 번째 실행을 수동으로 수행할 수 있습니다. "대시보드로 계속 이동" 버튼을 클릭하고 "크론 작업" 탭을 선택하세요.

여기에 /api/refresh-list가 있습니다. 기능을 클릭하려면 "실행" 버튼을 사용하세요.

기능이 완료되면 "프로젝트" 탭으로 이동하여 "도메인" 아래의 URL 중 하나를 클릭합니다. 그러면 브라우저에 필터링된 텍스트가 포함된 웹사이트가 열립니다. 그림 5와 같아야 합니다.

안전하고 지연 시간이 짧은 필터링을 위한 Vercel Edge Functions 및 Upstash Redis로 데이터 유출 방지 그림 5:필터링된 웹사이트

/api/filtered-data를 추가하면 URL에 추가하면 API 응답에도 작동하는 것을 볼 수 있습니다. 다음 예와 같아야 합니다:

{
 "text": "He slipped and fell on his [REDACTED]. Well, that wasn't very [REDACTED]y."
}

마지막으로 cURL을 통해 /api/filter에 요청을 보내면 엔드포인트에서 사용자 정의 텍스트를 필터링합니다. &lt;PROJECT>을 교체하세요. Vercel 프로젝트와 함께하세요.

$ curl -X POST https://<PROJECT>.vercel.app/api/filter \
 -H "Content-Type: application/json" \
 -d '{"text":"He fell on his butt."}'

응답:

{
 "text": "He fell on his [REDACTED]."
}

다음 단계

이 튜토리얼을 마친 후에는 데이터가 업데이트되었지만 cron 작업이 데이터베이스를 업데이트하지 않은 경우 어떻게 되는지 자문해 볼 수 있습니다. 잘 관찰했습니다!

cron 작업은 새로 고침 기능을 트리거하지만 여전히 일반 API 기능이므로 원하는 대로 호출할 수 있습니다.

실제 데이터 필터의 경우 데이터 변경에 대한 응답으로 함수를 트리거하고 싶을 수도 있지만 구현 세부 사항은 필터의 기반으로 사용하는 데이터 저장소에 따라 크게 달라집니다. 그러니 제작할 때 이 점을 명심하세요!

추가 자료

GitHub에서 전체 프로젝트를 찾을 수 있습니다.