MAC 주소
Media Access Control Address
네트워크 인터페이스의 고유 식별자. 48비트 하드웨어 주소. 이더넷, Wi-Fi에서 사용.
Media Access Control Address
네트워크 인터페이스의 고유 식별자. 48비트 하드웨어 주소. 이더넷, Wi-Fi에서 사용.
MAC 주소(Media Access Control Address)는 네트워크 인터페이스 카드(NIC)에 할당된 48비트(6바이트) 고유 식별자입니다. "물리 주소" 또는 "하드웨어 주소"라고도 불리며, 이더넷이나 Wi-Fi 같은 데이터 링크 계층(OSI 2계층)에서 장치를 식별하는 데 사용됩니다. 예시: 00:1A:2B:3C:4D:5E 또는 00-1A-2B-3C-4D-5E 형식으로 표기됩니다.
MAC 주소의 구조는 두 부분으로 나뉩니다. 앞 24비트(3바이트)는 OUI(Organizationally Unique Identifier)로, IEEE가 제조사에 할당한 고유 번호입니다. 예를 들어 00:1A:2B는 Apple에, 00:50:56은 VMware에 할당되어 있습니다. 뒤 24비트(3바이트)는 제조사가 각 장치에 부여하는 일련번호입니다. 이 구조 덕분에 전 세계 모든 네트워크 장치가 이론상 고유한 MAC 주소를 가집니다.
ARP(Address Resolution Protocol)는 IP 주소를 MAC 주소로 변환하는 프로토콜입니다. 같은 네트워크 내에서 통신할 때, 목적지의 IP 주소를 알더라도 실제 이더넷 프레임을 전송하려면 MAC 주소가 필요합니다. ARP는 "이 IP 주소를 가진 장치가 누구냐?"라고 브로드캐스트하고, 해당 장치가 자신의 MAC 주소로 응답합니다. 이 결과는 ARP 캐시에 저장되어 반복 조회를 방지합니다.
현대 네트워크 보안에서 MAC 주소 관리는 중요한 이슈입니다. MAC 주소 필터링으로 허용된 장치만 네트워크에 접근하게 할 수 있지만, MAC 스푸핑(위조)이 가능하므로 단독 보안 수단으로는 부족합니다. 프라이버시 보호를 위해 iOS, Android, Windows 10+ 등 최신 OS는 Wi-Fi 연결 시 랜덤 MAC 주소를 사용하는 기능을 제공합니다.
import uuid
import subprocess
import re
from getmac import get_mac_address # pip install getmac
# 로컬 장치 MAC 주소 조회
local_mac = ':'.join(re.findall('..', '%012x' % uuid.getnode()))
print(f"로컬 MAC: {local_mac}") # 예: 00:1a:2b:3c:4d:5e
# getmac 라이브러리 사용 (권장)
mac = get_mac_address()
print(f"기본 인터페이스 MAC: {mac}")
# 특정 인터페이스 MAC 조회
eth_mac = get_mac_address(interface="eth0")
wifi_mac = get_mac_address(interface="wlan0")
# 원격 호스트 MAC 조회 (같은 서브넷)
remote_mac = get_mac_address(ip="192.168.1.1")
print(f"게이트웨이 MAC: {remote_mac}")
# MAC 주소 형식 변환
def format_mac(mac, delimiter=":"):
"""MAC 주소 형식 변환: 00:1A:2B → 00-1A-2B"""
clean = mac.replace(":", "").replace("-", "").upper()
return delimiter.join(clean[i:i+2] for i in range(0, 12, 2))
# OUI 파싱 (제조사 식별)
def get_oui(mac):
"""MAC 주소에서 OUI(제조사 식별자) 추출"""
clean = mac.replace(":", "").replace("-", "")[:6].upper()
# 실제로는 IEEE OUI 데이터베이스 조회 필요
oui_db = {"001A2B": "Apple", "005056": "VMware", "001C42": "Parallels"}
return oui_db.get(clean, "Unknown")
print(format_mac("00:1a:2b:3c:4d:5e", "-")) # 00-1A-2B-3C-4D-5E
# MAC 주소 조회 (Linux)
ip link show # 모든 인터페이스 MAC
ip link show eth0 # 특정 인터페이스
cat /sys/class/net/eth0/address # 직접 읽기
# MAC 주소 조회 (macOS)
ifconfig en0 | grep ether # Wi-Fi 인터페이스
networksetup -getmacaddress Wi-Fi
# MAC 주소 조회 (Windows)
ipconfig /all # 모든 인터페이스
getmac # MAC 주소만 출력
# ARP 테이블 조회 (IP ↔ MAC 매핑)
arp -a # 전체 ARP 캐시
arp -n 192.168.1.1 # 특정 IP의 MAC
ip neigh show # Linux 최신 명령어
# ARP 캐시 삭제
sudo ip neigh flush all # Linux
arp -d * # macOS
arp -d 192.168.1.1 # 특정 항목 삭제
# MAC 주소 임시 변경 (Linux)
sudo ip link set dev eth0 down
sudo ip link set dev eth0 address 00:11:22:33:44:55
sudo ip link set dev eth0 up
# MAC 주소 변경 (macOS)
sudo ifconfig en0 ether 00:11:22:33:44:55
# OUI 조회 (제조사 확인)
# IEEE OUI 데이터베이스: https://standards-oui.ieee.org/
curl -s "https://api.macvendors.com/00:1A:2B"
# 응답: Apple, Inc.
const os = require('os');
const { exec } = require('child_process');
// 모든 네트워크 인터페이스 MAC 주소 조회
function getAllMacAddresses() {
const interfaces = os.networkInterfaces();
const macs = {};
for (const [name, addrs] of Object.entries(interfaces)) {
for (const addr of addrs) {
if (addr.mac && addr.mac !== '00:00:00:00:00:00') {
macs[name] = addr.mac;
break;
}
}
}
return macs;
}
console.log(getAllMacAddresses());
// { eth0: '00:1a:2b:3c:4d:5e', wlan0: '00:1a:2b:3c:4d:5f' }
// 기본 인터페이스 MAC 주소
function getDefaultMac() {
const interfaces = os.networkInterfaces();
for (const addrs of Object.values(interfaces)) {
for (const addr of addrs) {
if (!addr.internal && addr.family === 'IPv4' && addr.mac) {
return addr.mac;
}
}
}
return null;
}
// MAC 주소 유효성 검증
function isValidMac(mac) {
const regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
return regex.test(mac);
}
console.log(isValidMac('00:1A:2B:3C:4D:5E')); // true
console.log(isValidMac('001A2B3C4D5E')); // false
// ARP 테이블 조회 (Linux/macOS)
exec('arp -a', (error, stdout) => {
if (error) return console.error(error);
const entries = stdout.split('\n')
.filter(line => line.includes('at'))
.map(line => {
const match = line.match(/\((\d+\.\d+\.\d+\.\d+)\).*at\s+([0-9a-f:]+)/i);
return match ? { ip: match[1], mac: match[2] } : null;
})
.filter(Boolean);
console.log('ARP 테이블:', entries);
});
"ARP 캐시에 잘못된 MAC 주소가 남아있어서 패킷이 엉뚱한 장치로 가고 있습니다. arp -d로 캐시를 비우고 다시 확인해보세요. 만약 계속 문제가 발생하면 ARP 스푸핑 공격 가능성도 점검해야 합니다."
"MAC 주소 필터링만으로 네트워크 접근을 제어하는 건 권장하지 않습니다. MAC 스푸핑은 5분이면 가능하니까요. 802.1X 인증과 함께 사용하거나, NAC 솔루션을 도입하는 게 좋습니다. 최소한 동적 ARP 검사(DAI)는 활성화하세요."
"MAC 주소는 48비트 물리 주소로, 앞 24비트 OUI는 제조사 식별자, 뒤 24비트는 장치 고유번호입니다. ARP 프로토콜로 IP와 MAC을 매핑하는데, 같은 서브넷 내 통신에 필수입니다. 다만 MAC은 L2에서만 유효하고, 라우터를 거치면 변경됩니다."
MAC 주소는 쉽게 위조(스푸핑) 가능합니다. 공격자가 허용된 MAC 주소를 스니핑한 후 자신의 장치에 설정하면 필터를 우회합니다. 반드시 802.1X, WPA3-Enterprise 등과 병행하세요.
MAC 주소는 로컬 네트워크(L2)에서만 유효합니다. 라우터를 통과하면 출발지 MAC은 라우터의 MAC으로 교체됩니다. 인터넷 통신에서 원격 서버는 당신의 MAC 주소를 알 수 없습니다.
공격자가 가짜 ARP 응답을 보내 트래픽을 가로챌 수 있습니다. 스위치에서 Dynamic ARP Inspection(DAI)을 활성화하고, 중요 서버는 정적 ARP 엔트리를 설정하세요.
802.1X 포트 인증 + MAC 필터링 병행. 스위치에서 Port Security로 MAC 학습 제한. DAI와 DHCP Snooping으로 ARP 스푸핑 방지. 모바일 장치는 랜덤 MAC 기능 활용을 권장합니다.