서론

다른 회사도 다 그러는진 모르겠는데,, 이 회사에선 회사에서 진행하는 업무들을 '프로젝트' 로 구분하고, 프로젝트별로 매출/비용 등을 인지한다.
이를 위해선 하나의 법인 안에 합쳐져있는 예금, 카드, 세금계산서/계산서(이하 편의상 그냥 세금계산서.) 등에 대해 장부를 작성하면서 또한 각각 어떤 프로젝트에 속한지도 기록이 필요하다.

원랜 재무 직원이 진행을 했는데,, 회사가 커지고 프로젝트가 많아지니 감당이 안되어서, 각 부서별로 일단 세금계산서에 대해서만이라도 선처리를 해달라고 요청을 하게 되었다.

요청 내용은 대략 아래와 같다.
1. 세금계산서 목록을 홈택스에서 엑셀로 내려받는다
2. 엑셀에서 내 부서에 해당하는 항목들을 찾아 필터링 한다
3. 장부 작성용 계정과목도 분류한다. (eg, 가스수도비, 용역비, ...)
4. 회계 프로그램에 각 내용을 하나씩 입력한다. (전표 생성)

위 업무 요청을 위해 재무에서 만든 가이드 중 일부

홈택스와 엑셀과 회계 프로그램을 오가야하고, 없던 일이 생기는데다가 계정이니 뭐니 회계 용어도 알아야하고,,
게다가 본사 밖에선 회계 프로그램 이용을 위해서 VPN 까지 사용해야하니,,
그냥 포기해버리더라....ㅋㅋㅋㅋ

재무에선 점점 많아지는 일에 깔려 죽을라하고,, 각 부서에선 교육한다고 불러도 모르겠다고 멍 때리고 있고...
이렇게 삽질하고 있는걸 우연히 발견해서 해결해보기로 했다.

시스템 배경

이 회사에서 그룹웨어는 내가 만든 시스템을 사용하고 있는데, 그 기능 중 하나로 전자결재가 있고, 전자결재 이용 편의를 위해 홈택스 계산서 스크래핑 및 이를 첨부하는 기능이 있다.
단순히 가져와서 표시에 추가로 검색이나 수정 등 연관 계산서의 간편한 조회, 전자결재에 사용되었는지 여부 표시 등 이런저런 편의 기능이 들어가 있다. (좀만 다듬으면 다른 회사에도 팔아먹을 수 있지 않을까 생각했는데,, 팔기 위한 서비스 개발은 늘 어렵다ㅠㅜ)

해당 그룹웨어에 내가 구현해둔 세금계산서 조회 기능. 스크래핑도 직접 구현한 기능에 의존하다 보니 드물게 막힐 때가 있다ㅠ

아무튼 세금계산서 기능은 이미 있으니, 여기서 각 세금계산서에 대해 [프로젝트 설정, 과세 구분, 계정과목 설정] 기능을 지원해주고,
이렇게 입력된 정보를 [회계 프로그램에 밀어 넣어주기] 를 하는게 이번 프로젝트의 완성⭐️

그리고 블로그에서 이 카테고리의 취지가 그렇듯, 이 글을 쓰게 된 이유는 [회계 프로그램에 밀어 넣어주기] 와 관련되어 있다.

[프로젝트 설정, 과세 구분, 계정과목 설정]를 위한 프로젝트별 계정 과목 제약, 일괄 처리 등은 그냥 웹서비스로 만들면 되는거니까 대충 적당히 만들었다. 실무자들 불러다가 교육하고 피드백 정도가 남은 상황.

 

회계 프로그램

이 회사는 더X 사의 아이큐X 라는 시스템을 이용 중이다. (이름을 숨길 생각은 없지만 그렇다고 검색으로 떠서 좋을 것도 없으니 적당히 마스킹)

사내 PC 한대에 서버 프로그램 및 SQL Server 를 깔아두고, 각 작업자 PC 에선 이 서버로 접속해서 사용하는 구조이다.
최초 도입비를 좀 비싸게 받고, 이후엔 유지보수 비용으로 약간씩 받으며, 카드 등 스크래핑 모듈 정도는 주기적으로 업데이트 해주는 듯?

이전 지문 인식 소프트웨어가 그렇듯, 로컬에 설치된 서비스니까 접속 정보는 어떻게든 획득할 수 있다. 아니 그 이전에 그냥 인터넷에 공유가 되어 있더라.
다른 일로 이 회사 영업사원과 통화할 일이 있었는데, DB 직접 접속으로 활용하는건 다른 곳에서도 자주 있는 것 같더라. 회사 차원에서 반기진 않지만 그렇다고 막을 순 없으니 어쩔 수 없다,, 정도의 느낌? 차세대 서비스는 이런 문제가 좀 더 방어가 되어 있다고 하는데,,,

아무튼 이 서비스는 서버 PC에 대한 방화벽을 제대로 설정해두지 않으면, 비밀번호도 공개되어 있겠다 권한이 없는 직원도 데이터를 훔쳐갈 수 있는 상당히 취약한 구조이다. 물론 후술할 복잡한 작업을 다 했다는 가정하에. 현실적으론 일어나기 힘들 것 같긴 하다.
그래서 개인적으론 꽁꽁 막아두는 것 보단 이렇게 적당히 열려있어서 내가 손을 댈 수 있는 여지가 있는 환경을 선호한다 ㅎ
막아야 한다면 내가 막아도 되고...

우리에겐 DB스키마 정보가 없으니,, DB 에 접속하면 불친절한 테이블명과 컬럼명들을 한가득 마주하게 된다.

사용량으로 테이블을 선별하고, 이름을 추론하고 데이터와 비교하면서 나에게 필요한 정보를 하나씩 찾는 지루한 작업...

컬럼을 하나 찾으면, 아래와 같은 쿼리로 동일 컬럼이 있는 다른 테이블을 찾을 수도 있다. 이 생각을 못해서 처음엔 하나하나 한참을 헤맸었다ㅠ

SELECT
    t.name AS table_name,
    c.name AS column_name
FROM sys.tables AS t
JOIN sys.columns AS c ON c.object_id = t.object_id
WHERE c.name = N'찾으려는컬럼명' AND EXISTS (
      SELECT 1
      FROM sys.dm_db_partition_stats AS ps
      WHERE ps.object_id = t.object_id AND ps.reserved_page_count > 0
)

 

헤매다보니 대충 DB 내에서 현재 수집된 세금계산서, 등록된 전표, 전표의 승인 여부 등 필요한 데이터는 얼추 찾았다.
완벽한건 아니지만,, 필요한 정보만 어떻게든 가져오면 되고 당장 정확성이 엄청 중요하지 않기 때문에, 문제 발생시 수정해주면 되고..

 

데이터 입력

문제는 데이터 밀어넣기.
어떤 테이블과 어떤 컬럼에 정확한 값을 넣어주지 않으면 프로그램이 오작동을 할 수도 있다.

이번에도 프로그램의 작동 로직을 분석하면 되는데,, 지금은 결국 DB에 기록되는거니, SQL 쿼리만 잘 찾으면 된다.

MSSQL 에는 Extended Events 란게 있다. 활성화해두면 실행된 쿼리 등에 대한 정보에 대한 로그가 설정한 경로에 기록되고, 이 파일에 대해 다시 쿼리로 이벤트를 조회할 수 있다.

다만 이걸 활성화하려면 sysadmin 권한이 있는 계정이어야 하는데, 위에서 말한 기본 계정은 해당 권한이 없다.
어차피 로컬 시스템이니까, 어찌저찌 생성해주면 된다. 이 과정은 생략.

-- 이벤트 생성
CREATE EVENT SESSION [TempSqlLog] ON SERVER
ADD EVENT sqlserver.rpc_completed( -- 프로시저 실행
    ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name,  sqlserver.username)
),
ADD EVENT sqlserver.sql_batch_completed( -- SQL 쿼리 실행
    ACTION(sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_name,  sqlserver.username)
)
ADD TARGET package0.event_file(
    SET filename = N'C:\SqlLog\SqlLog.xel',
        max_file_size = 100,
        max_rollover_files = 10
);

-- 시작/종료
ALTER EVENT SESSION [ShoSqlLog] ON SERVER STATE = START;
ALTER EVENT SESSION [ShoSqlLog] ON SERVER STATE = STOP;

sql_statement_completed 란 이벤트도 있었는데 유의미한 데이터가 없었던 것 같아서 제외, 오래전에 한거라 기억이 잘 나진 않는다.

action 에서 client_app_name, database_name, username 은 큰 의미는 없지만, 그냥 넣어뒀다. client_hostname 정도는 분석 과정에서 다른 사용자의 실 사용이 혼동되니 필터를 위해 사용했고..

 

로그를 켜두고, 전표 등록을 하고, 로그를 끄고, 이벤트를 질의한다.

WITH x AS (
    SELECT CAST(event_data AS xml) AS xe FROM sys.fn_xe_file_target_read_file('C:\SqlLog\SqlLog*.xel', NULL, NULL, NULL)
)
SELECT
    xe.value('(event/@name)[1]', 'nvarchar(60)') AS event_name,
    DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), GETDATE()), xe.value('(event/@timestamp)[1]', 'datetime2(3)')) AS ts,
    COALESCE(
        xe.value('(event/data[@name="batch_text"]/value)[1]', 'nvarchar(max)'), -- sql_batch_completed
        xe.value('(event/data[@name="statement"]/value)[1]',  'nvarchar(max)')  -- rpc_completed (환경에 따라)
    ) AS sql_text
FROM x
WHERE
	xe.value('(event/action[@name="client_hostname"]/value)[1]', 'nvarchar(128)') = 'DESKTOP-....'
ORDER BY ts DESC;

 

이러면 실제 회계 프로그램이 실행하는 쿼리들을 확인할 수 있다.

내가 필요한 전표 입력엔 특정 프로시저를 호출하는걸 확인했다. 프로시저의 내부 쿼리는 암호화 저장되어 확인할 수 없었지만, 나도 똑같이 실행만 하면 되니까 프로시저의 내용물까진 필요없긴 하다.

이제 종류별로 전표 발행을 해보면서, 프로시저 호출시의 각 필드가 어떤 값인지 파악하고, 나도 동일하게 호출해주면 된다.


이렇게 데이터를 다루다보면 아래와 같은 재무제표들도 이것저것 만들어볼 수 있을 것 같긴 한데,,,
이건 아직 필요성을 못 느끼는 것 같기도 하고 나도 공부해야될게 많아져서 일단은 보류...

(아래 화면은 개발 중 시스템의 일부이긴 한데 값은 모두 AI 가 생성한 더미데이터이다.)

'프로젝트 모음' 카테고리의 다른 글

SUPREMA 지문 출입/근태기 연동  (0) 2026.09.21
전자책(EPUB) DRM 해제  (0) 2026.02.22
카테고리 프롤로그  (0) 2026.02.22

내가 몇몇 일을 봐주고 있는 회사 하나가 층별 출입 통제로 세콤 지문 단말을 사용하고 있었는데, 사옥을 리모델링하면서 8층은 엘리베이터에서 바로 접근이 가능해졌다.
그래서 엘리베이터에 8층 버튼은 그냥 눌러선 눌리지 않고, 지문 인증시에만 작동하도록 설치가 되어있었다.

그렇게 별 생각없이 살고 있었는데, 건물 관리 담당 직원을 보니 신규 직원 입퇴사시마다 건물 관리 보안용으로 세콤에 사용자 등록을 하고, 또 8층 엘리베이터 용으로 신규 직원들을 매번 모아 관리실에 가서 지문 등록을 또 따로 해주고 있더라.

지문 단말기는 Suprema 사의 BioStation L2 라는 장비로, 글 작성 시점 기준으론 지원 종료된 단말기이다.
관리실에는 Windows 서버, 엘리베이터에 장착된 L2 단말기, 등록용 L2 단말기와 이들을 연결하는 공유기로 구성되어 있다.

대충 이런 구조..

담당 직원이 매번 관리실로 가야하는 이 비효율과 퇴사 지원의 관리 문제, 그냥 시스템에 대한 관심이 생겨서, 개선할 방법이 없나 이래저래 살펴보았다.

 


시스템 구조, 사용자/지문 등록 방법

서버 PC 에 어떻게 하는지 살펴보니, 웹브라우저로 관리 페이지에 접속해서 사용자 등록, 등록 과정에서 지문 스캔을 누르면 옆에 있는 등록용 단말기가 반응하고, 지문을 입력할 수 있는 구조였다.

서버 PC 에선 로컬에 MariaDB, java 등을 설치하고 웹 서버가 구동되고 있었고, 서버 내 DB 정보를 단말기 간에 동기화 해준다. 서버가 꺼져있어도 각 단말기는 직전 동기화 정보 기준으로 정상 작동함.

BioStar 2 라는 관리용 웹 콘솔과, 사용자 추가 화면

그리고 엘리베이터까지 뜯어보진 않았지만,, 단말기 뒷쪽을 보면 전원, LAN, 릴레이 신호 출력 등을 연결할 수 있는 웨이퍼 커넥터들이 달려있다.
웹 장치 설정을 보면, 특정 이벤트마다 어떤 동작이 수행될지 정의할 수 있는데, 카드 / 지문 / PIN 등 각각 인증 성공시 릴레이로 신호 출력을 걸어둘 수 있다. 릴레이 출력에 문 개폐 등의 장치를 연결해두는 식인 듯. 우리는 엘리베이터에 8층이 눌리도록 배선되어 있겠지?

 

등록한 정보는 서버 PC 로컬에 설치된 MariaDB 에 저장된다.
사용자 관련 데이터는 암호화되어 있어서 DB 에 직접 접근해서 수정한다거나 읽어오는건 제한되지만 이 서버는 감사하게도 API 를 제공한다. 관련 내용은 아래에서 계속. 암호화 방식도 분석해서 복호화가 되긴 한다. 이 역시 아래에서 후술.

 

원격 접속

여튼 최초의 목적은 지문 하나 등록하자고 매번 관리실까지 내려가는 수고를 없애기!
서버 PC 의 웹서버에 접근할 수 있으면서, 지문 단말기가 그 서버 PC 와 같은 망에 있다면 관리실로 내려가는 수고를 없앨 수 있다.
두개의 망을 서로 연결하기 위해 사무실과 관리실까지 건물 내부 EPS 실에서 랜선을 내리니 마니 쌩쑈를 하다가,,

관리실의 공유기에서 서버PC 로 포트포워딩을 해두고, 단말에서 연결하는 서버의 주소를 공인 IP 로 설정해버렸다.

이렇게 하면 지문 단말도 어디에 있든 인터넷에만 연결되면 서버와 정상 연결이 된다.

‘장치에서 서버 연결’이 활성화되어있으면, 단말기에서 서버주소:포트/tcp 로 연결을 요청하고, 연결이 끊겼을 땐 10초? 30초? 잘 기억 안나는데 그 정도 텀을 두고 서버 연결을 시도한다.
연결 성공시 30초 단위로 ping 을 보내면서 연결을 유지하고, 서버에서 지문 인증 요청 등 요청을 보내면 이 채널을 통해서 단말로 명령을 보내고 단말이 작동하는 구조.

‘장치에서 서버 연결’을 끄는 경우엔 장치 포트가 사용되는 것 같은데, 굳이 테스트해보진 않았다.

등록용 단말기를 테스트한다고 집으로 가져왔는데, 여기서도 잘 작동하는 것을 확인…ㅎㅎㅎ
이제 관리실에 내려가지 않고도 지문 등록이 가능해졌다. 다만 서버 컴퓨터가 항상 켜져있어야 한다는 제약이 생김..

다만 BioStar 관리 웹페이지도 관리실 밖에서 접속이 가능하려면 설정이 추가로 필요하다. 기본적으론 해당 PC 에서만 접속이 가능하게 설정이 되어있기 때문.

BioStar 2 Setting 이라는 프로그램을 실행해서 Unified Gateway 를 실행해주면 nginx 를 통해 웹서버가 다시 구동된다.
내 기억엔 이 과정에서 바로 전체 인터페이스로 바인드하니 포트 포워딩만 하면 접속이 가능했던 것으로 기억하지만,, 아니라도 nginx 는 설정 파일 변경이 용이하니 설치 디렉토리에서 nginx 를 찾아 설정을 변경해주자.

 

BioStar API

이제 관리실에 내려가지 않고, 사무실에서 관리 웹페이지에 직접 접근해서 작업해도 되지만,, 다음 목표는 퇴사자 등 인원 관리의 효율화이다.
위에서 말했듯 이 시스템은 API 를 제공한다. API 내용에 대해선
 BioStar X API 문서 참고.
위의 BioStar 2 제어용 웹사이트 자체도 이 API 를 기반으로 작동하는 것 같다.

API 가 완벽한건 아닌 것 같지만,,, 사용자 목록 조회, 사용자 수정(지문 추가 등)/비활성화/삭제, 기기로 지문 스캔 요청 등은 모두 가능하다.
사용자 관리야 그러려니하고, 지문 등록 기준으론 다음 과정을 거치면 된다. 한개의 지문(fingerprint)은 등록시 2개의 스캔 결과(template)가 필요하다. 이는 이 가이드 - [BioStar 2 API] How to Add Fingerprint Credential to a User 에서 세부적으로 잘 알려주고 있다.

  1. 지문 스캔 두번 - Scan Fingerprint
    • API 를 호출하면, 요청에서 선택한 기기로 지문 인식해달라는 메시지가 바로 표시된다.
    • 정상 스캔시 지문의 퀄리티가 기준치를 충족하는지 확인. Web 에서 기본값은 80인 듯, API 이용한다면 직접 검증 필요
  2. 이미 등록된 지문과 일치하는 template인지 확인 - Verify Duplicate Fingerprint
    • 단말로 요청을 보내지 않고 서버에서 검사
  3. 스캔한 2개의 지문(template)이 동일한 지문이 맞는지 검증 - Verify Fingerprint Scan
  4. 사용자 정보에 해당 지문(2개의 template 쌍) 추가하여 수정 - User: Update
    • fingerprint_templates 에 기존값 포함하여 추가

이대로만 끝냈으면 글을 쓰지도 않았을 것,, 시스템 자체에 관심이 생겨서 좀 더 살펴봤다.

DB 암·복호화

로컬에 설치된 DB 는 어찌저찌 접속해도, 사용자 정보에 관한 부분은 대부분 암호화되어 있다.

biostar2_ac.t_usr

눈으로 보이다시피, &@~ 로 시작하면 암호화된 데이터.
BioStar 설치 폴더/util/enckey 에 BioStar.secure_communication.encryption_key 로 암호화를 하는데, 이 키를 그대로 쓰진 않고 여기다가 xor 및 시저 암호를 간단히 적용하여 key, iv 를 만들어낸다. AES + PKCS7 패딩으로 각 record 를 복호화하면 됨.

사실 API 로 가져오면 되니까 크게 필요는 없기도 하다.
이 DB를 그대로 쓴다면, 기기 동기화 시켜야하니 API 호출이 어차피 필요해지는데 API 상으로 사용자 정보는 충분히 잘 제공해준다.

API 서버를 안쓰고 자체 프로토콜로 구현한다고 치면 이 DB 를 쳐다볼 필요도 없고,,,

그래도 일단 작업해본 김에 이렇게 정말 간단하게만 남겨둠.

 

통신 프로토콜 분석

Suprema 는 위에서 내가 사용한, BioStar 2 서버를 사용하지 않고도 단말기를 제어할 수 있게 Device SDK 란걸 제공한다.
관련 문서는 BioStar Device SDK 에서 확인할 수 있고, 샘플 코드와 Windows/Linux 각 32bit/64bit 라이브러리를 제공한다. (ARM은 없지만…)

위에서 얘기한, ‘장치에서 서버 연결’ 를 설정해두면 기기에서 서버의 tcp 포트로 소켓을 연결한다. 초기 키 교환 이후 요청은 AES로 암호화하여 주고받는다.

  1. 서버는 연결되자마자 32B source_key 를 고정 키로 암호화하여 응답 반환
  2. 장비는 source_key 를 해싱하여 key, iv 생성, 이 후 상호 통신 간엔 AES-256-CBC 로 암호화하여 통신
    • 평문 20B + 암호화 데이터{ 헤더 16B + Payload }

SDK 에 통신 프로토콜에 대한 구조는 없어서, SDK 없이 직접 구현은 좀 까다롭다.

양측 통신을 서로 비교하고 SDK 문서나 구현을 참고하여 어찌저찌 Python 에서 작동하는 서버를 거의 다 만들었는데,,
새로 스캔한 지문 template 이 이미 등록된 지문인지 확인할 방법이 없다ㅠ (슈프리마에선 1:N 인증이라고 부르는 듯.)

위의 등록 과정에서 [2. 이미 등록된 지문과 일치하는 template인지 확인 - Verify Duplicate Fingerprint] 과정에 해당하는 구현인데,,
1:1 비교는 두 템플릿을 단말로 보내서 결과값을 받으니 기존 서버없이 사용이 가능한데, 1:N 인증에 대한 기능은 없다. 단말에 저장된 정보 기준으로 검사 및 반환이 가능할 것 같은데 말이지..ㅠㅠ

OSDP 라고, 다른 출입통제 시스템과 연동 사용하는 매뉴얼도 있던데 여기서도 2개 템플릿이 일치하는지 검사하는, 1:1 비교만을 지원한다.
템플릿 하나로 이게 등록된 사용자의 지문인지 비교하는
1:N 비교는 제공하지 않는다...

이 기능 하나가 없어서 기껏 만든게 모두 도로묵...ㅠㅠㅠ
의도적으로 제공하지 않는 것 같은데 이유는 잘 모르겠다.

 

지문 template 분석

지문 검사를 내가 직접해줄 순 없을까? 싶기도 하고 이 쯤 오니 궁금해져서, 지문 template 데이터도 분석해봤다.
template은 지문 스캔 이미지를 일부 전처리한 후 융선과 특징점을 추출한 데이터로, 최대 384B 의 데이터를 base64 인코딩되어 있다.

설정에 ISO (ISO 19794-2 일 듯), ANSI378 이란 포맷도 있던데,, 현재 기본 값은 Suprema 포맷.
OSDP 로 ANSI 포맷을 사용할 때도 템플릿은 최대 384B 로 제한하라는 문서가 있다. 내부 처리 한계인 듯.

Suprema 포맷은 UF Template 이라고도 불리는 것 같다.(그래서 이하 UF 포맷) 과거엔 UFMatcher.dll 이란 이름으로 별도 배포되다가, 지금은 biostar-server.exe 내부에 구현이 포함되어 있다.

UF 는 헤더(8B) + 특징점(4~5B * 개수) + 융선 방향장(셀 개수 만큼)으로 구성되어 있다.
헤더에 셀의 크기가 적혀있고, 1 ~ 63의 범위로 검사하지만, 내가 테스트한 장비 기준으론 지문 원본 이미지가 272x320(17x20 셀), template 이미지는 288x320(18x20 셀) 로 출력해주고 있었다.
템플릿 이미지가 오른쪽에 여백을 줄지언정 288px 로 고정출력되는거 보면 이게 최대 크기인 것 같긴 한데,, 다른 모델이면 더 큰 해상도로 줄 지는 모르는 일...

특징점은 셀이 아니라 template 이미지 기준(288x320) 특정 좌표와 거기서의 360도 각도 값, type 으로 추정되는 0, 1값, 그리고 비교할 때 사용하는 7비트 속성으로 이루어져있고,
융선은 셀 개수(18x20)만큼, 각 셀을 방향없이 길게 채우는 degree 값을 사용한다.

각 값들은 압축 정도에 따라 표시 범위가 제한되기도 하지만 그런거까진 생략.

지문 원본 이미지는 회색 음영인 PGM 포맷이고, 설정에서 지문 - 이미지 표시 활성화시 단말 기기에서 바로 볼 수 있는 이미지이다.
이 raw 이미지는 스캔시 받을 수 있도록 API 구조에 있긴 한데, 실제로 이미지를 주진 않았던 같다. (이런식으로 API 가 뭔가 구멍이 하나씩 빠져있다..ㅠ) 난 SDK 구현 이용해서 가져옴.

웹이나 API 사용시 기본적으로 template 을 이미지로 변환한, 두번째 형태의 이미지를 준다.

template 구조를 분석하면 3번째 이미지를 자체적으로 생성할 수도 있음. 세부 구조 분석 결과는 생략.


 

회사 그룹웨어에 구현

일단 다시 구현한 매칭 알고리즘을 사용하진 않고, BioStar API 만을 사용해서 회사 그룹웨어에 지문 등록, 수정 기능을 만들어두었다.
일단 이대로도 쓰는데 지장은 없지만,, 나중에 심심하면 좀 더 개선해봐야지...

장비만 좀 저렴하면 다른 용도(법인차량 키나 인감 도장 불출 등)로도 써먹고 싶은데, 인식기 대당 가격이 비싸서.. ㅠㅠㅠㅠ


매칭 알고리즘 분석

기능을 제공하지 않아서 답답하기도 하고, 수백명의 지문에서 어떻게 비교해서 결과를 내는지도 궁금해서 이것도 분석을 진행해봤다.

슈프리마 지원 문서에서는 FAR(다른 사람의 지문인데 오인식 매칭되는 확률)에 대한 문서가 있다.

1:N 보안 등급이 단말기 입장에선 보통, 높음, 가장 높음으로 구분되고, 서버에서 UFMatcher 가 비교하는건 1~7단계의 보안 등급이 있는 것 같다.

BioStar 웹 기기 설정 페이지에서의 지문 1:N 보안 등급 설정 메뉴

서버 매칭은 지문 개수에 따른 차이가 없긴 한데,, 느낌상 단말의 보통 = 서버 3, 단말 높음 = 서버 4, 단말 가장 높음 = 서버 5와 유사한 수준을 제공하나보다.
이 회사의 환경에서 기의 1:N 보안 등급은 보통으로 설정되어 있었고, 서버는 설정값을 찾진 못했지만 보안 레벨이 5로 작동하고 있었다.

이렇듯 서버와 단말기의 알고리즘이 조금 다른거 같긴 한데,, 단말기 로직 분석은 너무 어려울 것 같으니 서버 로직 분석만 진행.
ANSI 등 포맷의 검증 로직도 있지만 일단 난 UF 포맷만 확인하였음.

1:N 비교는 최악의 경우엔 전체 지문과 다 1:1 비교를 해야하더라. 대강 다음 순서로 진행된다.

  1. A, B 각 템플릿의 UF 포맷 헤더 상 특정 1B(raw[4]) 값의 차이를 구한다, 이 값의 절댓값이 낮은 순서부터 검사를 진행한다.
  2. 1차 비교
    • Fast 모드: 특징점을 최대 18개로 줄인 뒤, 거리(7)/상대 방향(20도) 오차 조건으로 대응점을 찾고 점수 계산, 50점 미만이면 탈락
    • 기본: 좀 더 엄격한 거리(4)/상대 방향(15도) 오차로 대응점을 찾고, 특징점 쌍 개수가 많으면 거리가 먼 쌍은 일부 제외, 60점 미만이면 탈락
  3. 2차 비교
    • 전체 특징점에 대해 거리(7)/상대 방향(20) 오차 조건으로 대응점을 찾고 점수 계산
    • 보안 등급에 따라 특정 점수(등급 5는 350점) 이상이면 합격
  4. 전체에서 최고점수를 찾진 않고, 보안 등급별 기준 점수를 넘기는 첫번째 항목이 나오면 해당 항목 반환
  5. 1:1 검증에서, 혹은 1:N 검증에서 일치 후보를 찾지 못했으며, 관련 설정이 켜져있는 경우(난 꺼져있음), 템플릿을 특정 로직으로 변환한 후 재검증

2번 이후야 결국 1:1 검사인 셈이고, 많은 지문 중에 어떻게 대상 지문을 빠르게 찾아내나 했는데, 1번 과정이 핵심인 것 같다.
저 1바이트의 값을 어떻게 생성하는지는 모름,,, 아쉽게도 지문 이미지 → 템플릿으로의 변환은 서버에 없고 단말에서만 수행하는 것 같다.

서버 쪽 설정은 여전히 없지만,, 단말 설정 기준 1:N Fast 모드가 자동, 보통, 빠름, 가장 빠름이 있다.
추정컨데, 가장 빠름: 1차 비교 + Fast 모드 / 빠름: 1차 비교 / 보통: 1차 비교 자체를 생략; 이지 않을까..?
현재 서버에선 1차 비교를 하되 Fast 모드 리샘플링은 안하더라.

 

얼추 따라 구현하긴 했는데,, 어차피 당장 사용할 구현은 아니라서 자세한 검증을 해보진 않았다.


이제 지문 이미지에서 template 으로 변환하는 로직만 알아내면 슈프리마 시스템과 호환되는 완전 자체 제작 장비를 만들 수도 있겠지만,,,!
나 혼자 쓰는거 외에 다른 곳에 쓸 수 있는 것도 아니고,, 그렇게 호환시킬거면 ANSI 포맷 같은걸 쓰면 되는게 아닌가,, 싶다..

최근에 디미고 학생이 지문 모듈로 교내 간편결제 솔루션을 만들었다는걸 보고 지문 인식 방식에 조금 관심이 있던 찰나 마침 이걸 하게 되어서 좀 더 쓸데없이 시간을 과투자하긴 했는데,, 뭐 나름 재밌었다.
나도 대학생 때 비슷한걸 하고 싶었지만 법적인 문제와 결국 은행과의 연동에서 포기했는데,, 디미고나 민사고에선 이걸(특히 법) 어떻게 해결했나 몰라,,, 그냥 따로 입금받고 학생이란 쉴드로 적당히 넘어가고 있으려나? ㅎㅎㅎㅎ

Odroid 공홈에서 판매중인 와이파이 모듈
공홈에서 CF-813B 의 OEM이며, Realtek RTL8821CU chipset 을 사용한다고 나와있다.

공홈에서 파는거니 확실히 지원이 보장되겠지만,, 크기가 조금 크기도 하고 결정적으로..

처음 꽂은 후로 뺄때 분리가 되어버렸다.......ㅠㅠㅠㅠ

조금 큰 본체가 마음에 안들기도 해서 대체품을 찾아봤는데,
무선랜이 은근히 드라이버를 많이 가린데서 조금 고민이 되었다.

다른 애들도 작동을 안하진 않을 것 같지만,, 일단 가능한 동일 칩셋으로 찾아본 제품이 NEXT-653WBT 이거.

블루투스 등 스펙도 동일하고, 연결시 드라이버도 동일하게 잡히고 잘 작동한다.
최저가 기준 가격도 조금 더 저렴하고,, 크기도 작고..!!

Ubuntu 24 + Odroid N2+ 에서 테스트해봤고,
Ubuntu 24 + NanoPi RS3 에서도 별다른 드라이버 과정없이 연결하자마자 작동하는 것 확인.

Ubuntu 24 + Odroid N2+ 기준, 위 2개 상품은 8821c 칩셋이고, 이 드라이버가 커널 내장이라 정상 작동한다.
iptime A3000MINI 의 경우 8822b 이고, 해당 드라이버가 Odroid 공식 배포 Ubuntu 24 배포판에 들어 있긴 한데,,,
zstd 압축이 되어 있는데, 커널이 압축된 드라이버 옵션이 빠진 채로 빌드되어 있어 로드되지 않는다.

테스트는 안해봤지만,, 압축만 해제해주고 재부팅하면 될 것 같음

# 8821cu 는 커널 내장이라 안해줘도 됨
# unzstd --keep /lib/firmware/rtw88/rtw8821c_fw.bin.zst
# 8822b
unzstd --keep /lib/firmware/rtw88/rtw8822b_fw.bin.zst

+ Recent posts