C.W.K.
Stream
Lesson 07 of 08 · published

Markdown 안의 HTML — 힘과 위험

~12 min · markdown, html, security, xss

Level 0평문
0 XP0/64 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Markdown 은 HTML 의 superset, 그 결과로...

CommonMark 는 inline HTML 과 block HTML 둘 다 허용. inline 태그 (<span>, <kbd>, <sub>, <sup>, <abbr>, <cite>) 는 Markdown 강조 동작하는 곳에서 작동. block 태그 (<div>, <table>, <details>) 는 앞뒤에 빈 줄 필요 해야 block 으로 다뤄져.

유용한 HTML

  • 이미지 크기 — Markdown 에 width 속성 없음; <img src="..." width="400" alt="..."> 사용.
  • 접을 수 있는 섹션<details><summary>Click</summary>...</details>. GitHub 에서 렌더링.
  • 키보드 단축키<kbd>Cmd</kbd>+<kbd>K</kbd> 가 스타일된 키 표시.
  • 아래/윗첨자H<sub>2</sub>O, x<sup>2</sup>.
  • 복잡한 테이블 — GFM 테이블이 못 할 때 (rowspan, colspan, 셀 안 block) <table> 로 떨어져.

XSS 경고

사이트가 사용자 제공 Markdown 을 렌더링한다면 (댓글, 위키, 포럼) 출력 HTML 을 sanitize 해야 해. sanitize 안 하면 댓글의 <script>alert(1)</script> 가 페이지의 진짜 스크립트 태그가 돼. GitHub 는 위험한 태그 떼어냄; 많은 정적 사이트 생성기는 안 해 (작성자가 신뢰됨 가정). 렌더러가 어느 쪽인지 알고 써.

원칙: 신뢰된 작성자의 Markdown 은 어떤 HTML 도 OK. 신뢰 안 된 작성자의 Markdown 은 server-side sanitize 필수 (rehype-sanitize, DOMPurify, bleach, sanitize-html). '클라이언트에서 sanitize 할게' 는 리팩토링 한 번 만에 터지는 XSS 취약점이야.

Code

유용한 inline HTML·markdown
Press <kbd>Cmd</kbd>+<kbd>K</kbd> to open the palette.

The formula is H<sub>2</sub>O, not H<sup>2</sup>O.

See <abbr title="Common Mark">CM</abbr> spec for details.
접을 수 있는 details (GitHub 에서 렌더링)·markdown
<details>
<summary>Click to expand the long stack trace</summary>

```
Traceback (most recent call last):
  File "app.py", line 42, in <module>
    main()
  File "app.py", line 37, in main
    raise ValueError("boom")
ValueError: boom
```

</details>
크기 지정 이미지·markdown
<img src="./architecture.png" alt="System architecture diagram" width="600">
코드에서 sanitize (rehype, JS)·javascript
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'

const html = String(
  await unified()
    .use(remarkParse)
    .use(remarkRehype, { allowDangerousHtml: true })
    .use(rehypeSanitize)  // strips <script>, on* attrs, etc.
    .use(rehypeStringify)
    .process(userMarkdown)
)

External links

Exercise

오래된 README 열어서 Markdown 만으로 부족한 곳 찾아 — 작게 만들고 싶은 이미지, 접고 싶은 stack trace, 스타일하고 싶은 키보드 단축키. inline HTML 로 작성하고 GitHub 에서 렌더링 확인. 그리고 자문해봐: 모르는 사람이 내 사이트에 이 Markdown 을 쓸 수 있다면 같은 HTML 이 여전히 OK 일까? 그 gap 이 sanitization 결정.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.