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↩︎로 교환 가능

좋은 웹페이지 즐겨찾기