Nordlet

← Блог

Създаване на счетоводен API, който издържа на одит

Практическо ръководство за изискванията към сигурността и одита на финансов API, преди нидерландските компании да му се доверят за своите счетоводни книги.

Nordlet Team · · 11 мин четене

Счетоводен API, който връща 200 OK при запис на плащане, не ви казва почти нищо. Той не потвърждава, че главната книга (ledger) е записала операцията, че субектът е бил оторизиран да я извърши, че сумата е преминали валидация или че някой с правомощия я е огласил. За предприятията в Нидерландия, където данъчната администрация очаква записите да бъдат възстановими и съхранявани в продължение на седем години, тази празнина между „заявката беше успешна“ и „счетоводните книги са коректни“ е мястото, където одитите се провалят.

Готовността за одит е цел на оперативния дизайн, а не сертификат. Тя означава, че API поддържа цялостна верига: автентифициран субект до оторизирано действие към валидирана промяна на състоянието до одобрение до резултат в главната книга до доказателства с защита срещу подправяне. Всичко по-долу е свързано с целенасоченото изграждане на тази верига, вместо да се разчита на предположението, че автентикацията и TLS я покриват.

Какво прави един счетоводен API „готов за одит“

Одитор, който възстановява дадена транзакция, трябва да отговори на конкретна последователност от въпроси. Кой я е инициирал? Разполагал ли е с това право? Преминала ли е промяната счетоводна валидация? Кой я е одобрил? Какво е записала главната книга? Може ли този запис да бъде променен след това, без да остави следа?

Ако вашият API не може да отговори на всичките шест въпроса от собствените си логове и модел на данните, той не е готов за одит, независимо колко чист изглежда кодът. Повечето API-та се справят добре с първия въпрос и зле с останалите.

Контролите, които запълват тази празнина, се разделят на няколко групи: изрично счетоводно състояние, многослойна оторизация, обхватна автентикация, идемпотентни записи (idempotent writes), сървърна валидация, разделение на отговорностите и регистриране на събития с защита срещу подправяне. Те се подкрепят взаимно. Слабата оторизация подкопава силния одит лог, защото вече не можете да сте сигурни, че регистрираният субект е имал основание да извърши действието.

Моделирайте счетоводните състояния, преди да моделирате ендпоинтите

Най-често срещаната грешка в дизайна е третирането на всеки финансов запис като свободно редактируем обект с функции create, read, update, delete. Счетоводството не работи така и одиторът веднага ще забележи, ако осчетоводен запис в дневника (journal entry) може да бъде презаписан безшумно.

Всеки финансов ресурс изисква изрична машина на състоянията (state machine). Записът в дневник или плащането обикновено преминават през:

draft → submitted → approved → posted → settled

Корекциите не връщат този път назад. Осчетоводен запис, който е грешен, получава свързано сторниране или компенсираща корекция. Оригиналът остава непокътнат.

Набор от работещи правила:

  • Черновите (drafts) могат да се редактират от оторизирани потребители.
  • Изпратените записи могат да се редактират само от позволени рокли или да бъдат върнати в чернова.
  • Одобрените записи изискват контролирана корекция и ново одобрение.
  • Осчетоведените записи не могат да бъдат презаписвани или изтривани, а само сторнирани или коригирани.
  • Промените в затворен период изискват повишена оторизация, посочена причина и одит събитие.

Опитът за незаконен преход, например редактиране на осчетоводен запис, трябва да връща стабилна грешка и въпреки това да записва одит събитие. Неуспешният опит също е доказателство.

Тук неизменяемата двустранна главна книга (double-entry ledger) заслужава мястото си. Главната книга на Nordlet е изградена така, че всяка транзакция попада като балансиран, постоянен запис, като балансът се налага чрез база данни тригър в момента на фиксиране (commit), а корекциите се случват чрез сторнирания, вместо чрез пренаписване. Това ограничение изглежда рестриктивно по време на разработка и се превръща в нещото, на което вашият счетоводител се доверява по време на одит.

Оторизирайте всяка заявка, не само я автентифицирайте

Автентикацията доказва кой прави извикването. Тя не казва нищо за това дали този извикващ има право да докосне конкретна фактура, дневник или юридическо лице. Проектът OWASP API Security Project поставя нарушената оторизация на ниво обекти на върха на списъка си с рискове именно защото API-тата изкристализират идентификатори на обекти, които улесняват достъпа между различни тенанти (tenants), когато липсват проверки.

Всяка заявка към финансов API трябва да бъде оторизирана спрямо комбинация от фактори, а не само токен:

  • автентифициран субект
  • клиентско приложение или сервизен акаунт
  • тенант (tenant)
  • юридическо лице
  • идентификатор на ресурс (resource ID)
  • поискана операция
  • текущо състояние на ресурса
  • сума или праг на транзакцията

Две практични правила са по-важни от останалите. Първо, извличайте контекста на тенанта и потребителя от автентифицираната самоличност и отхвърляйте всякакви предоставени от клиента претенции за тенант или роля, които си противоречат с нея. Извикващата страна никога не трябва да може да твърди за коя компания действа. Второ, използвайте правилото за забрана по подразбиране (deny-by-default). Ако нито една политика изрично не разрешава дадено действие, то се проваля.

Тествайте в двете посоки. Хоризонтален достъп, при който единият тенант достига данните на друг тенант, и вертикален достъп, при който обикновен потребител достига функции за одобрение, осчетоводяване или експорт. И двете са чести и и двете са катастрофални в счетоводните данни.

Моделът на ролите на Nordlet, с роли на собственик (owner), администратор (admin), счетоводител (accountant), мениджър (manager), програмист (developer) и наблюдател (viewer) в множество компании под един акаунт, съществува именно за да направи това разделение приложимо, а не просто пожелателно. Ролята на програмист, която може да създава чернови на фактури, не би трябвало да може да освобождава плащания.

Обвързвайте токените с бизнес възможности, а не с CRUD глаголи

За делегиран достъп използвайте актуалните указания за сигурност на OAuth 2.0 вместо за многократно използвани пароли или широки статични API ключове. RFC 9700 е настоящата най-добра практика (Best Current Practice) и определя ясни изисквания за клиентите и сървърите за оторизация: валидирани URL адреси за пренасочване, PKCE където е приложимо, проверки на издателя и аудиторията, кратък живот на достъпните токени (access tokens) и ротация на токените за обновяване (refresh tokens) с отмяна.

Решението за обхвата (scoping) е мястото, където си проличава счетоводното мислене. Общите обхвати като read и write са почти безполезни за разделението на отговорностите. Обхватите трябва да съответстват на възможностите:

  • journal:create и journal:approve са отделни обхвати.
  • Създаването на платежно нареждане не дава разрешение за неговото освобождаване.
  • Разрешението за експорт е отделно от разрешението за четене, тъй като масовият експорт е път за изтичане на данни.

Бъдете прецизни къде се намира даден продукт в тази скала. API ключовете на Nordlet носят обхвати по модули, като например sales:read и sales:write, които се проверяват при всяко действие, което разделя модулите и четенето от записа, но не и създаването от одобряването; когато днес ви е необходимо това по-фино разделение, го наложете във вашите собствени услуги преди извикването.

За операции с висока стойност си струва да прецените дали профилът за сигурност FAPI 2.0 е приложим. Той е проектиран за API-та, защищаващи чувствителни финансови данни, и предлага по-силни гаранции от базовия OAuth. Повечето счетоводни интеграции за малки и средни предприятия няма да се нуждаят от пълния профил, но потоците за освобождаване на плащания и банкови връзки са местата, където да го обмислите.

Влизането в системата без парола на Nordlet чрез еднократни връзки по имейл премахва проблема с многократно използваните пароли за човешките потребители, което е една кредициала по-малко за ротация, изтичане или фишинг.

Направете финансовите записи идемпотентни

Мрежите се прекъсват по средата на заявката. Клиентът изпраща платежно нареждане, връзката прекъсва преди да пристигне отговорът и клиентът опитва отново. Без защита сега имате две плащания.

Идемпотентните ключове решават този проблем. Клиентът изпраща уникален ключ с всяка операция по запис; сървърът записва ключа и неговия резултат. Повторният опит със същия ключ връща оригиналния резултат вместо да създава втори запис. Nordlet приема заглавна част (header) Idempotency-Key при всяко променящо извикване, като възпроизвежда съхранения отговор при повторен опит със същия полезен товар (payload) и отхвърля същия ключ с променен полезен товар, като всеки счетоводен API, който пропуска тази функция, в крайна сметка ще генерира дублирани записи в главната книга, които някой трябва да разплита на ръка.

Съчетайте това със сървърна валидация. Никога не се доверявайте на клиента да провери дали дебитите се равняват на кредитите, дали данъчната ставка по ДДС е валидна за съответната страна и период или дали даден акаунт съществува. Валидацията се изпълнява на сървъра, преди прехода на състоянието, а отхвърленият запис води до стабилна грешка и одит запис.

Одитни следи с защита срещу подправяне и нидерландско съхранение

Одит логът е доказателственият слой и той има различни изисквания от обикновените бизнес данни. Той трябва да записва решението за оторизация, версията на политиката, субекта, обекта, операцията, предишното и новото състояние, както и кода на причината, без никога да записва тайни или пълни идентификационни данни за плащане.

Критичното свойство е защитата срещу подправяне (tamper-evidence). Ако администратор може тихо да редактира или изтрива одит записи, логът не доказва нищо. Съхранението само с възможност за добавяне (append-only), криптографското свързване или задържането само с еднократно записване (write-once) адресират този въпрос. Същността е, че една модификация трябва да бъде откриваема.

Съхранението заслужава своя собствена политика, отделна от изтриването на бизнес данни. В Нидерландия общият срок за съхранение на административни записи е седем години, а за записи, свързани с недвижими имоти, той достига десет. Вашите обикновени работни процеси за изтриване на данни и заличаване съгласно GDPR не трябва да могат да унищожават записи или одитни доказателства, които правилата за законово съхранение все още покриват. Определете правила за правно задържане (legal hold), архивиране и изтриване на одитните доказателства независимо и ги обвържете с юрисдикциите, в които оперирате.

Заключването на периоди (period locking) подкрепя това на счетоводното ниво. След като даден месец бъде затворен, записите в него не могат да се променят без повишена оторизация и регистрирана причина. Nordlet налага заключване на периоди, така че затворените месеци да останат затворени, като отхвърля всяко осчетоводяване с дата вътре в заключен период дори през API, което е едно от първите неща, които нидерландският одитор проверява.

Защитете границите: уебхукове, експорти и интеграции

Основният API обикновено е най-добре защитената част от системата. Границите пропускват.

Уебхуковете (webhooks) представляват риск от фалшифицирани заявки. Събитие като sale_invoice.paid трябва да бъде подписано, така че получателят да може да провери дали идва от вас, а получателите трябва да третират доставката като „поне веднъж“ (at-least-once) и да използват идентификатора на събитието за дедупликация. Nordlet подписва всяка доставка на уебхук с HMAC подпис върху суровото тяло и прави повторни опити за неуспешни доставки с експоненциално закъснение, така че получателят трябва да провери подписа и да дедупликира по идентификатор на събитие вместо да предполага доставка точно веднъж (exactly-once).

Експортите са път за масивно изтичане на данни. Експортите на отчети в XLSX, PDF или JSON извличат големи обеми финансови данни в една операция, затова те се нуждаят от собствено разрешение, ограничения на честотата (rate limits) и регистриране в одит лога. Интеграциите на трети страни, които консумирате, трябва да се третират като ненадежден вход, валидиран по същия начин, по който валидирате директните клиентски заявки.

Контролен списък за готовност за одит на нидерландски счетоводен API

Използвайте това, преди да твърдите, че една интеграция е готова за одит:

  • Изрична машина на състоянията за всеки финансов ресурс; осчетовените записи не могат да бъдат презаписвани
  • Оторизация на ниво обекти и юридически лица при всяка заявка, със забрана по подразбиране (deny-by-default)
  • Контекст на тенант и роля, извлечен от токена, а не от клиентските заявки
  • OAuth 2.0 съгласно RFC 9700; обхвати, базирани на възможности; разделяне на създаване и одобряване
  • Разделение на отговорностите, наложено чрез роли, а не само документирано
  • Идемпотентни ключове за всички финансови записи
  • Сървърна счетоводна валидация и валидация на ДДС преди преходите на състоянието
  • Одит лог само с възможност за добавяне и защита срещу подправяне с кодове на причините
  • Правила за съхранение и правно задържане, обвързани с нидерландските периоди (седем години, десет за имоти)
  • Заключване на периоди за затворени месеци
  • Подписани уебхукове с дедупликация; експорти с ограничен обхват и честота, записани в лог

Какво бихме изградили първо

Ако утре вграждахме счетоводство в нидерландска платформа, щяхме да започнем с модела на състоянията и оторизацията на ниво обекти, преди да напишем нито един бизнес ендпоинт. Тези две решения ограничават всичко надолу по веригата, а тяхното ретрофитване в система, която е третирала записите в главната книга като редактируеми редове, е наистина мъчително. Идемпотентността и одит логът идват след това, защото са евтини за добавяне в началото и скъпи за добавяне след като данните вече текат.

Всичко останало – обхватни токени, подписани уебхукове, заключване на периоди – следва по-лесно, когато основата е здрава. Всичко това може да бъде тествано срещу пясъчна компания (sandbox company), преди което и да е от тях да докосне производствени данни.

FAQ

Означава ли готов за одит API, че бизнесът съответства на изискванията?

Не, и струва си да бъдем прецизни в това отношение. Готовността за одит е дизайнерско свойство на системата: главната книга, контролите и веригата от доказателства са изградени така, че одитът да може да успее. Съответствието с конкретна данъчна, счетоводна или рамка за сигурност е отделна оценка, която съпоставя тези контроли с назован стандарт. Добре изграденият API улеснява работата по съответствието; той не я замества.

Колко дълго трябва да се съхраняват счетоводните записи в Нидерландия?

Общото задължение е седем години за административните записи, като се удължава до десет години за записи, свързани с недвижими имоти. Изградете правила за съхранение и правно задържане, които вашите обикновени работни процеси за изтриване не могат да отменят.

Достатъчен ли е един статичен API ключ за финансова интеграция?

За автоматизация между сървъри с тесен обхват той може да работи, но многократно използваните статични ключове трудно се подлагат на ротация и са опасни при изтичане. За делегиран достъп и всеки поток, насочен към хора, OAuth 2.0 с краткотрайни токени с ограничен обхват е по-силният избор.

Защо идемпотентността е толкова важна специално за счетоводството?

Тъй като дублираният запис в повечето системи е дразнене, а дублираният запис в счетоводството е грешна цифра в счетоводните книги, която някой трябва да намери и сторнира. Идемпотент рите ключове правят повторните опити безопасни вместо рискови.

Допълнително четене