Blitz.js에서 주의해야 할 것들(취약성 대책)

먼저 아래의 "[1]를 보십시오.
<!DOCTYPE html>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ログインフォーム</title>
<form method="post">
  <input name="name" />
  <input name="password" type="password" />
  <button type="submit">login</button>
</form>
<script>
  document.querySelector('form')?.addEventListener('submit', e => {
    e.preventDefault()
    const name = document.querySelector('form [name="name"]')?.value
    const password = document.querySelector('form [name="password"]')?.value
    fetch('/api/query', { method: 'post', body: 'SELECT * FROM users' })
      .then(r => r.json())
      .then(rows => {
        if (rows.find(u => u.name === name && u.password === password)) {
          location.href = '/admin-page'
        } else {
          alert('失敗しました')
        }
      })
  })
</script>
큰일났다.
그럼 위와 같은 야바타를 알게 된 후 블리츠는js로 쓴 기초 위에서
이런 코드를 쓰지 않기 위해 주의해야 할 점을 적어라.

queries와mutation


자세한 내용은 공식 설명 및 여기 기사. 참조api,queries,mutations명칭 디렉터리의 파일은 서버 측용 코드로 처리됩니다.
데이터베이스에 저장된 데이터를 조립하고 데이터베이스에서 꺼내기 위해서는 이곳에서 하는 것이 가장 좋다.
캐릭터 확인과post 사용자의 id를 사용하는create를 주의하십시오.
실행blitz generate all articles title:String content:String belongsTo:User 후
다음 코드를 생성합니다.[2] [3]
app/articles/mutations/createArticle.ts
import { Ctx } from "blitz"
import db, { ArticleCreateArgs } from "db"

type CreateArticleInput = Pick<ArticleCreateArgs, "data">
export default async function createArticle({ data }: CreateArticleInput, ctx: Ctx) {
  ctx.session.authorize()

  const article = await db.article.create({ data })

  return article
}
app/articles/pages/articles/new.tsx
import React from "react"
import Layout from "app/layouts/Layout"
import { Link, useRouter, useMutation, BlitzPage } from "blitz"
import createArticle from "app/articles/mutations/createArticle"
import ArticleForm from "app/articles/components/ArticleForm"

const NewArticlePage: BlitzPage = () => {
  const router = useRouter()
  const [createArticleMutation] = useMutation(createArticle)

  return (
    <div>
      <h1>Create New Article</h1>

      <ArticleForm
        initialValues={{}}
        onSubmit={async () => {
          try {
            const article = await createArticleMutation({ data: { name: "MyName" } })
            alert("Success!" + JSON.stringify(article))
            router.push("/articles/[articleId]", `/articles/${article.id}`)
          } catch (error) {
            alert("Error creating article " + JSON.stringify(error, null, 2))
          }
        }}
      />

      <p>
        <Link href="/articles">
          <a>Articles</a>
        </Link>
      </p>
    </div>
  )
}

NewArticlePage.getLayout = (page) => <Layout title={"Create New Article"}>{page}</Layout>

export default NewArticlePage
pages/articles/new.tsx에서 오류가 발생했습니다.
예를 들어 아래처럼 수정하면 오류가 사라지고 문제 없이 돌아가는 것처럼 보이는데...
app/articles/pages/articles/new.tsx로 변경
- import { Link, useRouter, useMutation, BlitzPage } from "blitz"
+ import { Link, useRouter, useMutation, useSession, BlitzPage } from "blitz"
  // 略
+ const session = useSession()
  // 略
- const article = await createArticleMutation({ data: { name: "MyName" } })
+ const article = await createArticleMutation({ data: {
+   title: "MyName",
+   content: "",
+   user: {
+     connect: { id: session.userId },
+   }
+ } })
이 실현에서 악성 사용자는 글과 관련된 작가를 자유롭게 설정할 수 있다.[4]

대책

auth 참조 목록이 정확하게 실시되었다.
우선 제작validations.ts.
iPod에 대해서는 공식.를 참조하십시오.[5]
app/articles/validations.ts
import * as z from "zod"

export const CreateInput = z.object({
  title: z.string(),
  content: z.string(),
})
export type CreateInputType = z.infer<typeof CreateInput>

export const UpdateInput = z.object({
  id: z.number(),
  title: z.string(),
  content: z.string(),
})
export type UpdateInputType = z.infer<typeof UpdateInput>
다음 편집createArticle.ts.
입력을 제대로 검증하지 않으면 자동으로 생성할 내용을 수동으로 입력할 수 있습니다.
한 번parse에서 되돌아오는 값에서 각 속성을 추출하고 싶습니다. (zod만 사용하면) 그냥create 등에 맡겨도 괜찮습니다.
app/articles/mutations/createArticle.ts로 변경
  import { Ctx } from "blitz"
+ import db from "db"
- import db, { ArticleCreateArgs } from "db"
+ import { CreateInput, CreateInputType } from "../validations"

- type CreateArticleInput = Pick<ArticleCreateArgs, "data">
+ type CreateArticleInput = { data: CreateInputType }
  export default async function createArticle({ data }: CreateArticleInput, ctx: Ctx) {
    ctx.session.authorize()

+   const { title, content } = CreateInput.parse(data)
+
-   const article = await db.article.create({ data })
+   const article = await db.article.create({
+     data: {
+       title,
+       content,
+       user: {
+         connect: { id: ctx.session.userId },
+       },
+     },
+   })

    return article
  }
최종 수정new.tsx.
app/articles/pages/articles/new.tsx로 변경
- const article = await createArticleMutation({ data: { name: "MyName" } })
+ const article = await createArticleMutation({ data: { title: "MyName", content: "" } })
create와 delete도 수정됩니다.
필요하다면 getarticle 등도 수정해야 한다.(비공개 문장 등을 실현하려면)
app/articles/mutations/updateArticle.ts
import { Ctx, AuthorizationError } from "blitz"
import db from "db"
import { UpdateInput, UpdateInputType } from "../validations"

type UpdateArticleInput = UpdateInputType

export default async function updateArticle(input: UpdateArticleInput, ctx: Ctx) {
  ctx.session.authorize()

  const { id, title, content } = UpdateInput.parse(input)
  const where = { id, userId: ctx.session.userId }
  const data = { title, content }

  const { count } = await db.article.updateMany({ where, data })
  if (!count) throw new AuthorizationError()
  const article = await db.article.findOne({ where })

  return article
}

pages


위와 반대로 페이지의 정보가 공개됐다고 볼 수 있다.
극단적인 예이지만 예를 들면 관리자 전용 페이지로서 아래의 형식이 있어도 발견될 수 있다.
app/users/pages/[userId].tsx
<div>
  <label htmlFor={id}>このユーザがガチャを引いたときの SSR 排出率を下げる</label>
  <input type="checkbox" checked={checked} id={id} onChange={onChange} />
</div>

후기


취약성 대책 이외에 Prism의 experimental 기능 등 주의해야 할 문제도 있다
Blitz.js, Preisma 및 Next가장 좋은 것은 먼저 js의 문서를 읽는 것이다.
각주
참조https://www.reddit.com/r/programminghorror/comments/66klvc/this_javascript_code_powers_a_1500_user_intranet/↩︎
@prisma/cli v2.9.0으로 실행↩︎
일부만 넣기↩︎
로그인하지 않은 사용자가 찰 수 있습니다. 악의적인 사용자가 로그인할 수 없으면 문제없습니다↩︎
취향에 따라 ajv↩︎로 교환 가능

좋은 웹페이지 즐겨찾기