internal AttributeWrapper(GumboAttribute attribute, ElementWrapper parent, int index, Action<string, ElementWrapper> addElementWithId) { if (parent == null) { throw new ArgumentNullException("parent"); } if (addElementWithId == null) { throw new ArgumentNullException("addElementWithId"); } Parent = parent; Index = index; Name = NativeUtf8Helper.StringFromNativeUtf8(attribute.name); Value = NativeUtf8Helper.StringFromNativeUtf8(attribute.value); OriginalName = NativeUtf8Helper.StringFromNativeUtf8(attribute.original_name.data, (int)attribute.original_name.length); OriginalValue = NativeUtf8Helper.StringFromNativeUtf8(attribute.original_value.data, (int)attribute.original_value.length); NameStart = attribute.name_start; NameEnd = attribute.name_end; ValueStart = attribute.value_start; ValueEnd = attribute.value_end; Namespace = attribute.attr_namespace; if (String.Equals(this.Name, "id", StringComparison.OrdinalIgnoreCase)) { addElementWithId(this.Value, parent); } }
internal AttributeWrapper(GumboAttribute attribute, ElementWrapper parent) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } Parent = parent; Name = NativeUtf8Helper.StringFromNativeUtf8(attribute.name); Value = NativeUtf8Helper.StringFromNativeUtf8(attribute.value); OriginalName = NativeUtf8Helper.StringFromNativeUtf8(attribute.original_name.data, (int)attribute.original_name.length); OriginalValue = NativeUtf8Helper.StringFromNativeUtf8(attribute.original_value.data, (int)attribute.original_value.length); NameStart = attribute.name_start; NameEnd = attribute.name_end; ValueStart = attribute.value_start; ValueEnd = attribute.value_end; Namespace = attribute.attr_namespace; }
private bool ValidateNode(ElementWrapper node, InsertionsMap insertionsMap, ref RequestValidationParam dangerousParam) { var result = true; foreach ( var element in node.Children.OfType<ElementWrapper>()) { var elementStart = (int)element.StartPosition.offset; var elementEnd = (int)element.EndPosition.offset; foreach ( var insertionArea in insertionsMap.Where(ia => ia.Includes(elementStart, elementEnd))) { // Check if start position of node was included to insertions map if (insertionArea.Includes(elementStart)) { // Inclusion found (node was injected by request parameter) dangerousParam = insertionArea.Param; return false; } foreach (var attr in element.Attributes) { var attrNameStart = (int)attr.NameStart.offset; if (insertionArea.Includes(attrNameStart)) { // Inclusion found (attribute was injected by request parameter) dangerousParam = insertionArea.Param; return false; } var attrValueStart = (int)attr.ValueStart.offset; var attrValueEnd = (int)attr.ValueEnd.offset; // Skip if attribute value wasn't tainted by request parameter if (!insertionArea.Includes(attrValueStart, attrValueEnd)) continue; // Skip if attribute value passes validation if (ValidateAttribute(attr.Name, attr.Value, insertionArea.Param.Value)) continue; // Attribute value is dangerously tainted dangerousParam = insertionArea.Param; return false; } } if (element.Tag == GumboTag.GUMBO_TAG_SCRIPT && element.Children.Any(child => child is TextWrapper)) { var text = element.Children.OfType<TextWrapper>().FirstOrDefault(); if (text != null) { // Validate javscript code inside <script /> tag foreach ( var insertionArea in insertionsMap.Where( ia => ia.Includes((int) text.StartPosition.offset, (int) text.StartPosition.offset + text.Text.Length)) .Where(insertionArea => !ValidateJavascript(text.Text, insertionArea.Param.Value))) { // Javascript code is dangerously tainted dangerousParam = insertionArea.Param; return false; } } } // TODO: Add integrity validation of style nodes here result &= ValidateNode(element, insertionsMap, ref dangerousParam); } return result; }
private void AddElementWithId(string id, ElementWrapper element) { List<ElementWrapper> elements; if (!ElementsWithIds.TryGetValue(id, out elements)) { elements = new List<ElementWrapper>(); ElementsWithIds.Add(id, elements); } elements.Add(element); }
private static void MarshalElementAndDescendants(ElementWrapper element) { GC.KeepAlive(element.Attributes); foreach (var child in element.Children.OfType<ElementWrapper>()) { MarshalElementAndDescendants(child); } }