<a> 태그와 <Link> 태그의 차이점지역 설명 모달에서 오른쪽 하단에 위치한 '숙소'와 '항공권' 버튼에 외부 사이트를 연결할 때, <Link> 태그를 사용하려고 했다.
그런데 외부 URL을 연결할 때는 <a> 태그를 쓰는 게 안전하다고 해서, <a> 태그와 <Link> 태그의 차이점에 대해서 알아봐야겠다고 생각했다.

| 항목 | <a> 태그 | <Link> 태그( react-router-dom 기준) |
|---|---|---|
| 역할 | 하이퍼링크 (전통적인 웹 방식) | 클라이언트 사이드 라우팅 (SPA 방식) |
| 전체 페이지 새로고침 | O (기본 동작) | X (히스토리만 바꿈) |
| 사용 위치 | HTML 어디서나 | React 앱 내부에서만 (.tsx, .jsx, .js 등의 React 컴포넌트 파일 안에서만) |
| 사용 방법 | <a href="/about">About</a> | <Link to="/about">About</Link> |
| 의도 | 외부 또는 서버 내 URL 이동 | 리액트 라우터 내 컴포넌트 전환 |
| 기능 | 브라우저가 직접 이동 처리 | 라우터가 JS로 이동 처리 |
| 예시 | 페이지 전체를 새로 로딩해야 하는 외부 링크나, 비-SPA 사이트에 유용 | React SPA 내부에서 빠르게 화면 전환이 필요할 때 유용 (이전 상태도 유지됨) |
📁 public/
└── index.html ← 이건 React 외부. 여기선 <a>만 사용 가능
📁 src/
└── App.tsx ← 이건 React 내부. 여기서만 <Link> 사용 가능
└── components/
└── Header.tsx ← 이것도 React 내부
<Link> 태그로 외부 URL 연결하면 안 되는 이유<Link>는 SPA 내부 라우팅 전용
<Link> : Single Page Application(SPA)에서 페이지 새로고침 없이 내부 경로로 이동하기 위한 컴포넌트/about, /product/123, /mypage<Link>는 내부 이동 시 브라우저 전체를 다시 렌더링하지 않고, 라우터 상태만 바꿔줌외부 URL을 <Link to="https://..." />처럼 쓰는 건 문제가 될 수 있는 이유
예외적인 동작 가능성
<Link>는 내부 경로를 history.push()로 처리하는데, 외부 URL에서는 이 방식이 맞지 않아 예상치 못한 동작이 발생할 수 있음
의도와 다름
외부 URL은 페이지 전체를 새로 로드해야 하는데 <Link>는 그걸 막으려 하기 때문에, 브라우저 전체를 새로 여는 동작이 자연스럽지 않음
리디렉션 오류 가능성
react-router가 외부 URL을 내부 URL로 잘못 해석해서 라우팅 에러가 날 수 있음
SEO & 접근성 이슈
<a> 태그는 웹 크롤러와 스크린리더가 외부 링크로 인식하지만, <Link>는 그렇지 않을 수 있음
그래서 외부 URL은 반드시 <a>로 써야 할까?
맞다🙆. 외부 링크는 HTML의 <a> 태그를 사용하는 것이 표준이고 안전하다.
<a href="https://www.booking.com" target="_blank" rel="noopener noreferrer">
숙소
</a>
rel="noopener noreferrer"의 의미noopenertarget="_blank"일 때)가 열린 쪽 페이지(window.opener)에 접근하지 못하게 막음// A.html에서 B.html을 새 창으로 열었을 때
const newTab = window.open('https://example.com');➡️ 이 경우 example.com은 window.opener를 통해 A.html을 제어할 수 있음// B.html
window.opener.location = 'https://phishing.com'; // 피싱 가능 즉, 사용자가 클릭한 링크가 악성 사이트였다면, 기존 창(A.html)을 피싱 사이트로 바꿀 수 있는 심각한 보안 위험이 생김rel="noopener"을 설정하면 이걸 차단함noreferrerReferer: https://my-site.comnoreferrer는 이런 정보 노출을 차단함noopener vs. noreferrer 정리
| 속성 | 보호 대상 | 주요 기능 | 필요 상황 |
|---|---|---|---|
noopener | 내 사이트 | window.opener 차단 (이전 창 조작 방지) | 보안 위협 방지 |
noreferrer | 사용자 프라이버시 | Referer 헤더 제거 | 개인정보 보호 |
target="_blank"를 쓸 때 함께 사용함<a href="https://example.com" target="_blank" rel="noopener noreferrer">링크 열기</a>rel="noopener" 속성이 없을 때 생기는 보안 문제문제 상황 데모
index.html : 원래 페이지 (사용자 사이트)<!-- index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>My Website</title>
</head>
<body>
<h1>안전한 사이트</h1>
<a href="attacker.html" target="_blank">새 창으로 이동</a>
</body>
</html>attacker.html : 외부 악성 페이지 (공격자 사이트)<!-- attacker.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>악성 페이지</title>
<script>
// 창이 열리자마자 이전 창을 공격
if (window.opener) {
window.opener.location.href = "https://phishing-site.com";
}
</script>
</head>
<body>
<h1>이 페이지는 이전 창을 조합니다!</h1>
</body>
</html>동작 흐름
index.html에서 링크를 클릭해서 attacker.html을 새 탭으로 엶attacker.html은 window.opener를 통해 index.html을 조작함window.opener.location.href = "https://phishing-site.com"에 의해 원래 창이 피싱 사이트로 바뀜rel="noopener" 추가<a href="attacker.html" target="_blank" rel="noopener">새 창으로 이동</a> 이렇게 하면 attacker.html의 window.opener는 null이 되기 때문에 이전 창을 조작할 수 없음