HotXLS nekter å rute 20 farlige formelnavn, blant dem CALL, REGISTER.ID, WEBSERVICE og DDE, videre til dine Delphi user-function-callbacks med mindre du sier deg selv ja til det. Arbeidsbokegenskapen AllowUnsafeFormulaCallbacks står som standard til False, sjekken kjører før noe argument evalueres, og et avvist kall rapporterer xlfeUnsafeFunctionDenied uten å aktivere én eneste handler
Scenariet som gjorde dette nødvendig, er helt hverdagslig. En tjeneste tar imot opplastede XLS- eller XLSX-filer, rekalkulerer dem på serversiden og leser noen totalsummer tilbake. Vertsapplikasjonen registrerte en OnUserFunction-handler for år siden for et par forretningsfunksjoner, og et sted på veien fikk den handleren en catch-all-gren som videresender alt den ikke gjenkjenner, til en plugintabell. Ingen på teamet skrev noensinne =WEBSERVICE(...) i en celle. Opplasteren gjorde det. Å holde den formelen intakt gjennom åpning, rekalkulering og lagring er en filtroverdighetsfunksjon. Å la den nå kode i verten som kan åpne sockets eller filer, er en autorisasjonsbeslutning, og helt til HotXLS skilte de to, tok biblioteket den beslutningen stille på dine vegne
Hvorfor ble det å bevare en formel tillatelse til å kjøre den?
Rotårsaken var én enkelt fallback-sti. HotXLS parser hvert Excel-funksjonsnavn det kjenner, men ikke hvert kjente navn har en implementasjon i beregningsmotoren. Innebygde funksjoner som ble gjenkjent, men ikke implementert, endte tidligere i samme user-defined function-fallback som ekte egendefinerte navn, så CALL og REGISTER.ID delte en dispatch-sti med dine DISCOUNT eller REGIONRATE. Ukjente navn som WEBSERVICE eller DDE kunne på samme måte treffe en likes navngitt oppføring i arbeidsbokens register, det prosessomfattende registeret eller en eventhandler. Mekanikken i den fallback-en er dekket i hvordan HotXLS løser opp egendefinerte funksjoner gjennom OnUserFunction; problemet var at ingenting på den stien spurte om navnet selv var en funksjon et fornuftig program noensinne burde kjøre
Dispatch-rekkefølgen betyr noe for hva «ukjent» betyr her. Et kall motoren ikke kan evaluere nativt, tilbys i tur og orden leksikale LAMBDA- og LET-bindinger, som closure-støtten i HotXLS formelmotor løser opp først, deretter arbeidsboklokale funksjoner registrert med RegisterUserFunction, så prosessomfattende funksjoner fra TXLSWorkbook.RegisterGlobalUserFunction og til slutt hendelsene OnUserFunction og OnUserFunctionEx. Først når alle sier nei, blir en virkelig ukjent funksjon til #NAME?. Hvert trinn etter lambda-oppslaget gir kontrollen til kode du har skrevet, og det er nøyaktig derfor sikkerhetssjekken må sitte foran hele kjeden i stedet for inne i én vilkårlig handler
Hvilke funksjonsnavn blokkerer HotXLS som standard?
XLSFormulaCallbackIsUnsafe i lxCalc.pas holder et fast nevningssett på 20 navn: 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 og FILE.DELETE. Det er navnene som, i Excel eller makrospråket dets, laster inn native kode, når nettverket, snakker med andre prosesser eller rører filsystemet. Før sammenligningen trimmer funksjonen omkringliggende mellomrom, konverterer navnet til store bokstaver og stripper ett enkelt _XLFN.- eller _XLWS.-prefiks, så _xlfn.webservice skrevet av en nyere Excel-versjon fanges opp akkurat som den bare stavemåten. Listen bor ved kalkulatorgrensen i stedet for i Classic-, XLSX- og ODS-parserne, noe som holder én AST, én BIFF-tokenstrøm og én konvertert arbeidsbok til å oppføre seg identisk
To kanter er verdt å kjenne før du støtter deg til den. Treffen er eksakt, så en handler du registrerer som MYWEBSERVICE, berøres ikke, og motsatt blir en lovlig intern UDF som tilfeldigvis heter OPEN eller RUN, nå avvist som standard. Nevningssettet er heller ikke en sandkasse for dine egne handlere. Kjører catch-all-grenen din vilkårlige pluginnavn, stopper gaten de beryktede farlige og ingenting annet; den varige fiksen er fortsatt en handler som matcher en eksplisitt tillatelsesliste med SameText og lar Handled stå på False for alt den ikke eier
Hvorfor må gaten kjøre før argumentevaluering?
En gate som utløses etter at argumentene er beregnet, kommer for sent, fordi argumentene i seg selv kan kalle koden din. GetValueItemUserFunction sjekker navnet først og avslutter med lxErrorUnsafeFunctionDenied før den bygger argumentmatrisen, før den rådfører seg med en resolver eller et av registrene, og til og med før den legger merke til at ingen handler i det hele tatt er tilordnet. Den rekkefølgen er det som beseirer det nestede tilfellet under, der det ytre kallet ville blitt nektet likevel, men en uskyldig utseende indre UDF ellers ville utløst først og etterlatt bieffekten sin
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'); // bieffekt i vertskoden
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, og FAuditLog er fortsatt tom
Arbeidsbokstandard versus per-kall TXLSFormulaEvaluationOptions
Arbeidsbokflagget er standarden, og per-kall-valget har siste ord. TXLSWorkbook.AllowUnsafeFormulaCallbacks og TXLSXWorkbook.AllowUnsafeFormulaCallbacks styrer vanlig rekalkulering, Calculate, den toargument EvaluateFormulaAt-varianten, evalueringsmaler, skrivebeskyttede visninger og, på XLSX, hver worker i det parallelle rekalkuleringsbassenget. Ethvert inngangspunkt som tar imot en eksplisitt TXLSFormulaEvaluationOptions-record, behandler Options.AllowUnsafeFormulaCallbacks som kjennelsen for det kallet og OR-er den ikke sammen med arbeidsbokegenskapen. Den asymmetrien er bevisst: en betrodd intern jobb kan autorisere ett RTD-oppslag uten å vippe hele arbeidsboken, og en arbeidsbok som er globalt optet inn, kan fortsatt tvinge en sensitiv evaluering tilbake til avslag
var
Options: TXLSFormulaEvaluationOptions;
Eval: TXLSFormulaEvaluationResult;
begin
// arbeidsboken forblir låst, ett betrodd kall slippes gjennom
Book.AllowUnsafeFormulaCallbacks := False;
Options := XLSDefaultFormulaEvaluationOptions;
Options.AllowUnsafeFormulaCallbacks := True;
Eval := Sheet.EvaluateFormulaAt(4, 2, '=WEBSERVICE(B1)', xlfrsA1, Options);
// arbeidsboken er optet inn, men denne evalueringen av opplastet tekst er det ikke
Book.AllowUnsafeFormulaCallbacks := True;
Options := XLSDefaultFormulaEvaluationOptions; // flagget er False igjen
Eval := Sheet.EvaluateFormulaAt(4, 2, UploadedFormula, xlfrsA1, Options);
if Eval.Status = xlfeUnsafeFunctionDenied then
LogRejected(Eval.Issue.Message);
end;
Å veksle arbeidsbokegenskapen merker også avhengighetsgrafen som skitten i begge motorer. Uten det steget kunne et cachet resultat beregnet mens callbacks var tillatt, blitt servert etter at de var trukket tilbake, eller et cachet xlfeUnsafeFunctionDenied-utfall kunne leve lenger enn en opt-in. Den nye statusen ble lagt til bakerst i TXLSFormulaEvaluationStatus etter xlfeFailed, så den har ordinal 10, og hver eksisterende ordinal beholder verdien sin; den samme legg-bakerst-regelen gjelder feltet i options-recorden og getteren og setteren i IXLSWorkbook, selv om en konsument bygget mot en eldre utgivelse fortsatt trenger rekompilering
Hva skjer med ukjent og utrygg formeltekst ved lagring?
Å beholde en formel og å kjøre den er nå to adskilte spørsmål, og inngangspolicyen svarer bare på det første. FormulaEntryPolicy på begge arbeidsbokklassene bærer UnknownFunctionMode og UnknownNameMode, begge med standardverdien xlfusmReject, så å tildele en formel med et ukjent kall gjennom den vanlige Formula-egenskapen avvises før celleverdien, formel-cachen eller avhengighetene endres. ValidateFormulaEntry rapporterer den samme kjennelsen uten bieffekter. Betrode stier som filinnlesing, kopiering og formatkonvertering går utenom den brukerbaserte inngangspolicyen, fordi et strengt standardvalg aldri må avvise symboler som allerede finnes i en fil du bare åpner
var
Policy: TXLSFormulaEntryPolicy;
begin
Policy := Book.FormulaEntryPolicy;
Policy.UnknownFunctionMode := xlfusmPreserve; // kompatibilitetsinngang
Book.FormulaEntryPolicy := Policy;
Sheet.Cells[3, 1].Formula := '=ACME_RATE(B3)'; // lagret, ikke autorisert
Book.SaveAs('rates.xls');
end;
I Classic BIFF8 har et ukjent kall ingen egen token, så HotXLS skriver det slik Excel skriver tilleggsfunksjoner. Formelen får en PtgNameX-token ($59) hvis XTI-oppføring peker på tilleggs-SUPBOOK-en med begge arkindekser satt til $FFFE, etterfulgt av argumenttokenene og en PtgFuncVar som bærer funksjonsnummer 255 og et argumentantall som inkluderer navneplassen. Den underliggende ExternName-kroppen er seks nullbyte, en lengdebyte og Unicode-flagg, UTF-16-funksjonsnavnet, deretter en to-byte-formel av $1C $17, en PtgErr som holder #REF!. Skriveren nekter navn lengre enn 255 tegn, mer enn 29 argumenter, og BIFF5-målet. Hvordan HotXLS klassifiserer disse tilleggs-SUPBOOK-oppføringene ved siden av eksterne arbeidsboklenker, er forklart i SUPBOOK- og XTI-klassifiseringsreglene for BIFF eksterne lenker. XLSX beholder rå funksjonstekst og ODS beholder msoxl:-formelen sin, og i hvert format åpnes en fil som lagret =WEBSERVICE(...) igjen med teksten intakt og evalueres fortsatt til xlfeUnsafeFunctionDenied som standard
Evaluerer pipelinen din arbeidsbøker den ikke selv har forfattet, la AllowUnsafeFormulaCallbacks stå på False, hold handlere på en eksplisitt tillatelsesliste, og gi per-kall-valg bare der formelkilden er din egen. Hele callback-, inngangspolicy- og evaluerings-API-et er dokumentert hos HotXLS Delphi spreadsheet-komponenten