A HotXLS megtagadja húsz veszélyes képletnév — köztük a CALL, a REGISTER.ID, a WEBSERVICE és a DDE — átirányítását az Ön Delphi felhasználói függvény callbackjeihez, hacsak Ön maga nem engedélyezi. A munkafüzet AllowUnsafeFormulaCallbacks tulajdonsága alapból False, az ellenőrzés még bármely argumentum kiértékelése előtt lefut, és egy elutasított hívás xlfeUnsafeFunctionDenied-et jelent anélkül, hogy egyetlen kezelőt is meghívná
A forgatókönyv, amely szükségessé tette ezt, hétköznapi. Egy szolgáltatás fogadja a feltöltött XLS vagy XLSX fájlokat, szerveroldalon újraszámolja őket, és néhány összeget visszaolvas. A gazdaalkalmazás évekkel ezelőtt regisztrált egy OnUserFunction kezelőt néhány üzleti függvényhez, és valahol útközben ebből a kezelésből kinőtt egy mindent-felfaló ág, amely minden fel nem ismertet egy bővítménytáblára továbbít. A csapat egyik tagja sem írt soha =WEBSERVICE(...)-t cellába. A feltöltő igen. A formula érintetlenül tartása nyitás, újraszámolás és mentés során fájlhűségi funkció. Az, hogy elérhesse azt a gazdakódot, amely socketeket vagy fájlokat nyithat, engedélyezési döntés, és amíg a HotXLS el nem választotta a kettőt, a könyvtár csendben hozta meg ezt a döntést az Ön helyett
Hogyan lett a formula megőrzéséből engedély a futtatására?
A gyökérok egyetlen tartalék útvonal volt. A HotXLS minden ismert Excel függvénynevet elemz, de nem minden ismert névnek van implementációja a számítómotorban. A felismert, mégis implementálatlan beépítettek ugyanabba a felhasználó által definiált függvény tartalékba hullottak, mint a valódi egyedi nevek, így a CALL és a REGISTER.ID ugyanazon a diszpécselő útvonalon utazott, mint az Ön DISCOUNT-ja vagy REGIONRATE-je. Az olyan ismeretlen nevek, mint a WEBSERVICE vagy a DDE, hasonlóan párosulhattak azonos nevű bejegyzéssel a munkafüzet-jegyzékben, a folyamatszintű jegyzékben vagy egy eseménykezelőben. E tartalék mechanikáját a a HotXLS egyedi függvényfeloldásáról az OnUserFunction útján szóló cikk írja le; a probléma az volt, hogy semmi sem kérdezte meg ezen az útvonalon, vajon maga a név-e az, amelyet egy ép elméjű gazda valaha futtasson
A diszpécselési sorrend azért fontos, mert meghatározza, mit jelent itt az „ismeretlen". Egy hívást, amelyet a motor natívan nem tud kiértékelni, sorban felajánlanak a lexikális LAMBDA és LET kötéseknek, amelyeket a HotXLS képletmotorjának closure-támogatása old fel elsőként, majd a RegisterUserFunction-nal regisztrált munkafüzet-helyi függvényeknek, ezután a TXLSWorkbook.RegisterGlobalUserFunction-ból érkező folyamatszintű függvényeknek, végül az OnUserFunction és OnUserFunctionEx eseményeknek. Csak ha mindannyian elhárítják, válik egy valóban ismeretlen függvény #NAME?-té. Minden, a lambda-keresés utáni szakasz az Ön által írt kódnak adja át az irányítást, és pontosan ezért kell a biztonsági ellenőrzésnek az egész lánc elé ülnie, nem valamelyik kezelőbe
Melyik függvényneveket zárja el a HotXLS alapból?
A lxCalc.pas XLSFormulaCallbackIsUnsafe függvénye húsz névből álló, rögzített tiltólistát hordoz: DDE, CALL, REGISTER, REGISTER.ID, WEBSERVICE, RTD, SQL.REQUEST, EXEC, RUN, CREATE.OBJECT, APP.ACTIVATE, SEND.KEYS, OPEN, SAVE, SAVE.AS, FOPEN, FWRITE, FWRITELN, FCLOSE és FILE.DELETE. Ezek azok a nevek, amelyek az Excelben vagy annak makrónyelvében natív kódot töltenek be, hálózatot érnek el, más folyamatokkal beszélnek vagy a fájlrendszerhez nyúlnak. Az összehasonlítás előtt a függvény levágja a környező whitespace-t, nagybetűssé teszi a nevet, és lehánt egyetlen _XLFN. vagy _XLWS. előtagot, így egy újabb Excel build által írt _xlfn.webservice is csapdázik, akárcsak a csupasz írásmód. A lista a számológép határán él, nem a Classic, XLSX és ODS elemzőkben, ami azt tartja meg, hogy egy AST, egy BIFF tokenfolyam és egy konvertált munkafüzet azonosan viselkedjen
Két széle érdemes ismerni, mielőtt ráépítene. Az egyezés pontos, tehát az Ön által MYWEBSERVICE-ként regisztrált kezelőt nem érinti, és fordítva: egy in-house UDF, amely épp OPEN vagy RUN névre hallgat, mostantól alapból elutasításra kerül. A tiltólista nem sandbox az Ön saját kezelői számára sem. Ha az Ön mindent-felfaló ága tetszőleges bővítményneveket futtat, a kapu a hírhedt veszélyeseket állítja meg, mást nem; a tartós javítás továbbra is olyan kezelő, amely explicit engedélylistára illeszt SameText-tel, és mindent, amit nem birtokol, Handled False-on hagy
Miért kell a kapunak az argumentumkiértékelés előtt futnia?
Egy kapu, amely az argumentumok kiszámítása után sül el, elkésik, mert maguk az argumentumok is meghívhatják az Ön kódját. A GetValueItemUserFunction előbb a nevet ellenőrzi, és lxErrorUnsafeFunctionDenied-nel lép ki, még mielőtt felépítené az argumentumtömböt, mielőtt bármely feloldóhoz vagy valamelyik jegyzékhez fordulna, és még azelőtt is, hogy észrevenné: egyáltalán nincs hozzárendelve kezelő. Ez a sorrend dönti le az alábbi beágyazott esetet, ahol a külső hívást úgyis elutasítanák, de egy ártalmatlannak tűnő belső UDF különben korábban elsülne, és maga mögött hagyná a mellékhatását
procedure TImportService.HandleUdf(Sender: TObject;
const FunctionName: WideString; const Args: Variant;
var Value: Variant; var Handled: Boolean);
begin
if SameText(FunctionName, 'AUDIT_TOKEN') then
begin
FAuditLog.Add('AUDIT_TOKEN evaluated'); // mellékhatás a gazdakódban
Value := 'token-42';
Handled := True;
end;
end;
Book.OnUserFunction := HandleUdf;
Eval := Sheet.EvaluateFormulaAt(1, 1, '=WEBSERVICE(AUDIT_TOKEN())');
// Eval.Status = xlfeUnsafeFunctionDenied, Eval.Value = Null,
// Eval.Issue.NativeCode = -106, és a FAuditLog még mindig üres
Munkafüzet-alapértelmezés kontra hívásonkénti TXLSFormulaEvaluationOptions
A munkafüzet-jelző az alapértelmezés, a hívásonkénti opció az utolsó szó. A TXLSWorkbook.AllowUnsafeFormulaCallbacks és a TXLSXWorkbook.AllowUnsafeFormulaCallbacks a rendes újraszámolást, a Calculate-ot, a kétargumentumos EvaluateFormulaAt-ot, az értékelési sablonokat, a csak olvasható nézeteket és, XLSX esetén, a párhuzamos újraszámolási készlet minden munkását kormányozza. Bármely belépési pont, amely explicit TXLSFormulaEvaluationOptions rekordot fogad, az Options.AllowUnsafeFormulaCallbacks-t tekinti az adott hívás verdiktjének, és nem vonja össze VAGY-kapcsolattal a munkafüzet tulajdonságával. Ez az aszimmetria szándékos: egy megbízható belső feladat engedélyezhet egyetlen RTD-keresést anélkül, hogy az egész munkafüzetet átkapcsolná, és egy globálisan feliratkozott munkafüzet is kényszerítheti vissza egy érzékeny kiértékelés elutasítását
var
Options: TXLSFormulaEvaluationOptions;
Eval: TXLSFormulaEvaluationResult;
begin
// a munkafüzet lezárva marad, egy megbízható hívás átengedve
Book.AllowUnsafeFormulaCallbacks := False;
Options := XLSDefaultFormulaEvaluationOptions;
Options.AllowUnsafeFormulaCallbacks := True;
Eval := Sheet.EvaluateFormulaAt(4, 2, '=WEBSERVICE(B1)', xlfrsA1, Options);
// a munkafüzet feliratkozott, de a feltöltött szöveg e kiértékelése nem
Book.AllowUnsafeFormulaCallbacks := True;
Options := XLSDefaultFormulaEvaluationOptions; // a jelző megint False
Eval := Sheet.EvaluateFormulaAt(4, 2, UploadedFormula, xlfrsA1, Options);
if Eval.Status = xlfeUnsafeFunctionDenied then
LogRejected(Eval.Issue.Message);
end;
A munkafüzet tulajdonság átkapcsolása mindkét motorban piszkosnak is jelöli a függőséggráfot. Ennek a lépésnek a nélkül egy olyan gyorsítótárazott eredmény szolgálódhat ki, amelyet akkor számoltak, amikor a callbackek engedélyezve voltak, vagy egy gyorsítótárazott xlfeUnsafeFunctionDenied kimenete túlélné a feliratkozást. Az új státuszt a TXLSFormulaEvaluationStatus végére fűzték, az xlfeFailed után, így sorszáma 10, és minden meglévő sorszám megtartja értékét; ugyanez a végrefűzési szabály érvényes az opciórekord mezőjére és az IXLSWorkbook getterére és setterére is, bár egy régebbi kiadás ellenére épített fogyasztónak mégis újra kell fordulnia
Mi történik az ismeretlen és nem biztonságos képlet szöveggel mentéskor?
A formula megtartása és a futtatása mostantól két külön kérdés, és a belépési szabályzat csak az elsőt válaszolja meg. A FormulaEntryPolicy mindkét munkafüzetosztályon hordoz UnknownFunctionMode-ot és UnknownNameMode-ot, mindkettő alapértelmezése xlfusmReject, tehát egy ismeretlen hívású formula hozzárendelése a rendes Formula tulajdonságon keresztül elutasításra kerül, mielőtt a cellaérték, a képlet-gyorsítótár vagy a függőségek változnának. A ValidateFormulaEntry mellékhatások nélkül jelenti ugyanezt a döntést. A megbízható útvonalak, mint a fájlbetöltés, a másolás és a formátumkonverzió, kikerülik ezt a felhasználói belépési szabályzatot, mert egy szigorú alapértelmezés soha nem utasíthat el olyan szimbólumokat, amelyek már eleve ott vannak egy fájlban, amelyet Ön csak megnyit
var
Policy: TXLSFormulaEntryPolicy;
begin
Policy := Book.FormulaEntryPolicy;
Policy.UnknownFunctionMode := xlfusmPreserve; // kompatibilitási belépés
Book.FormulaEntryPolicy := Policy;
Sheet.Cells[3, 1].Formula := '=ACME_RATE(B3)'; // tárolva, nem engedélyezve
Book.SaveAs('rates.xls');
end;
A Classic BIFF8-ban egy ismeretlen hívásnak nincs saját tokenje, így a HotXLS úgy írja, ahogy az Excel a bővítményfüggvényeket. A képlet kap egy PtgNameX tokent ($59), amelynek XTI bejegyzése a bővítmény SUPBOOK-ra mutat, mindkét munkalapindex $FFFE-en, utána jönnek az argumentumtokenek és egy PtgFuncVar 255-ös függvényszámmal és olyan argumentumszámmal, amely magában foglalja a névhelyet. A mögöttes ExternName törzs hat nulla bájt, egy hosszbájt és Unicode-jelző, az UTF-16 függvénynév, majd egy kétbájtos képlet, a $1C $17, egy #REF!-et hordozó PtgErr. Az író 255 karakternél hosszabb nevet, 29-nél több argumentumot és a BIFF5 célt tagadja meg. Azt, hogy a HotXLS hogyan sorolja be ezeket a bővítmény SUPBOOK bejegyzéseket a külső munkafüzet-hivatkozások mellett, az a BIFF külső hivatkozásainak SUPBOOK- és XTI-besorolási szabályairól szóló cikk magyarázza el. Az XLSX megőrzi a nyers függvényszöveget, az ODS a msoxl: képletét, és minden formátumban egy olyan fájl, amely =WEBSERVICE(...)-t mentett, a szöveg érintetlenségével nyílik újra, és alapból továbbra is xlfeUnsafeFunctionDenied-re értékelődik
Ha az Ön folyamata olyan munkafüzeteket értékel ki, amelyeket nem ő írt, hagyja a AllowUnsafeFormulaCallbacks-ot False-on, tartsa a kezelőket explicit engedélylistán, és hívásonkénti opciókat csak ott adjon, ahol a képletforrás az Öné. A teljes callback-, belépésszabályzat- és kiértékelési API a HotXLS Delphi táblázatkezelő komponens mellett dokumentált