v1.11.8
Relio v1.11.8 — 검색어의 %와 _를 와일드카드가 아닌 글자로 처리
고객 검색창에 50%를 입력하면 50이 들어간 모든 고객이 나오고, _는 아무 글자 하나와 일치했으며, % 한 글자만 넣으면 목록 전체가 반환되었습니다. 입력한 그대로 찾을 방법이 없었습니다.
1. 원인
모든 자유 검색 질의가 사용자가 입력한 문자열을 SQL 안에서 그대로 이어 붙였습니다.
lower(c.name) LIKE '%'||lower($4)||'%'PostgreSQL의 LIKE에서 %는 임의의 문자열, _는 임의의 한 글자를 뜻합니다. 검색어에 포함된 이 두 글자가 패턴의 일부로 해석되어, 사용자가 찾으려던 글자가 아니라 와일드카드로 동작했습니다. 관리자 Audit Log 검색도 ILIKE로 같은 문제를 가지고 있었습니다.
| 검색어 | 수정 전 | 수정 후 |
|---|---|---|
50% |
50이 들어간 모든 레코드 |
이름에 50%가 든 레코드 |
AB_C |
ABxC, AB1C 등도 일치 |
AB_C가 든 레코드 |
% |
목록 전체 | %가 든 레코드 |
back\slash |
백슬래시가 이스케이프 문자로 소비됨 | back\slash가 든 레코드 |
SQL Injection은 아닙니다. 값은 처음부터 Bind Parameter로 전달되었고, 문제는 전달된 값이 패턴 문법으로 읽힌 것입니다.
2. 수정
crm.SearchPattern이 Go 쪽에서 패턴을 만듭니다. 백슬래시와%,_를 이스케이프한 뒤 앞뒤에%를 붙입니다- 자유 검색 7개 질의 — 고객, 영업기회, 리드, 제품, 담당자, 협업자, 관리자 Audit Log — 가 모두
LIKE $n ESCAPE '\'를 선언합니다 - 빈 검색어는 빈 패턴을 그대로 돌려줍니다. 각 질의 앞의
$n=''무필터 가드가 그대로 유지되므로, 검색어 없이 목록을 여는 동작은 이전과 동일합니다 - 대소문자 구분 없는 검색과 앞뒤 공백 제거 동작도 이전과 동일합니다
3. 재발 방지
새로 추가되는 검색이 조용히 같은 문제를 들여오지 않도록, internal/ 전체의 Go 원본을 훑어 ESCAPE 없는 LIKE·ILIKE를 발견하면 실패하는 Test를 두었습니다.
검증
- 단위 Test 3개 추가: 이스케이프 결과, 공백 검색어가 빈 패턴을 유지하는지,
ESCAPE없는 검색 질의 회귀 가드 - Go 전체 Test/Vet (
go test -race ./...,go vet ./...),gofmt - TypeScript Typecheck와 React Production Build
- 환경변수 계약(
check-env-contract.sh)과 외부 정적 Asset 차단(check-static-assets.sh)
업그레이드
DB Migration은 없습니다. 화면과 API 계약도 그대로이며, 저장된 데이터에는 영향이 없습니다.
검색 결과만 좁아집니다. 지금까지 %나 _가 든 검색어로 더 넓은 결과를 얻고 있었다면, 이번 Release 이후에는 입력한 문자열이 그대로 포함된 레코드만 나옵니다.
오프라인 이미지
| 항목 | 값 |
|---|---|
| Asset | relio-v1.11.8.tar.gz |
| Docker Image | relio:v1.11.8 |
| SHA-256 | c286ac3837e733b944c5c7e3c63202216cefd15a8319e95dd4b7faf3025b2fce |
| 압축 크기 | 36M |
| Architecture | linux/amd64 |
이 Release가 직접 제공하는 Asset은 위 Docker Image tar.gz 하나뿐입니다.
오프라인 서버에서 로드
gunzip -c relio-v1.11.8.tar.gz | docker load
docker image inspect relio:v1.11.8실행
# 최초 1회만 생성하고 비밀번호 관리 도구에 보관하세요.
ENCRYPTION_KEY="$(openssl rand -hex 32)"
docker run -d \
--name relio \
-p 8080:8080 \
-e POSTGRES_DSN="postgres://relio:password@postgres:5432/relio" \
-e BOOTSTRAP_ADMIN="admin" \
-e BOOTSTRAP_ADMIN_PASSWORD="ChangeMe-Immediately" \
-e ENCRYPTION_KEY="$ENCRYPTION_KEY" \
-v relio-data:/var/lib/relio \
relio:v1.11.8Relio Application이 받는 환경변수는 필수 3개(POSTGRES_DSN, BOOTSTRAP_ADMIN, BOOTSTRAP_ADMIN_PASSWORD)와 선택 1개(ENCRYPTION_KEY)뿐입니다.
ENCRYPTION_KEY를 설정하면 Personal Key와 SSO Client Secret이 재기동, 이미지 교체, relio-data Volume 재생성 후에도 유지됩니다. 설정하지 않으면 자격증명을 여는 Key가 Volume 안에만 존재하므로 /var/lib/relio를 PostgreSQL과 같은 복구 시점으로 반드시 보존해야 합니다.
검증
Release 전에 Source Test, TypeScript Typecheck, Frontend Build, Go Vet, 환경변수 계약, 외부 정적 Asset 차단, 비 Root 실행, 완전 격리 Network 신규 설치 Smoke Test, 이전 Release 업그레이드 Test, Docker Save/Load 재검증을 통과합니다.